Best Practices für die Wiederverwendung von Code zwischen Controllern in Ruby on Rails

82

Ich habe einige Controller-Methoden, die ich gerne teilen möchte. Was ist die beste Vorgehensweise, um dies in Ruby on Rails zu tun? Sollte ich eine abstrakte Klasse erstellen, die meine Controller erweitern, oder sollte ich ein Modul erstellen und es jedem Controller hinzufügen? Im Folgenden sind die Controller-Methoden aufgeführt, die ich freigeben möchte:

def driving_directions
  @address_to = params[:address_to]
  @address_from = params[:address_from]
  @map_center = params[:map_center_start]

  # if we were not given a center point to start our map on
  # let's create one.
  if !@map_center && @address_to
    @map_center = GeoKit::Geocoders::MultiGeocoder.geocode(@address_to).ll
  elsif !@map_center && @address_from
    @map_center = GeoKit::Geocoders::MultiGeocoder.geocode(@address_from).ll
  end
end

def printer_friendly
  starting_point = params[:starting_point].split(',').collect{|e|e.to_f}
  ne = params[:ne].split(',').collect{|e|e.to_f}
  sw = params[:sw].split(',').collect{|e|e.to_f}
  size = params[:size].split(',').collect{|e|e.to_f}
  address = params[:address]

  @markers = retrieve_points(ne,sw,size,false)
  @map = initialize_map([[sw[0],sw[1]],[ne[0],ne[1]]],[starting_point[0],starting_point[1]],false,@markers,true)
  @address_string = address
end
Kyle Boon
quelle
1
Gibt es in diesem Fall einen bestimmten Grund, application.rb nicht zu verwenden?
PJ.
4
Nur dass einige Controller den Code verwenden, aber nicht alle.
Kyle Boon

Antworten:

113

Meiner Meinung nach gelten die normalen OO-Designprinzipien:

  • Wenn es sich bei dem Code wirklich um eine Reihe von Dienstprogrammen handelt, die keinen Zugriff auf den Objektstatus benötigen, würde ich in Betracht ziehen, ihn in ein Modul einzufügen, das separat aufgerufen werden soll. Wenn der Code beispielsweise alle Zuordnungsdienstprogramme enthält, erstellen Sie ein Modul Mapsund greifen Sie auf folgende Methoden zu : Maps::driving_directions.
  • Wenn der Code den Status benötigt und in jedem Controller verwendet wird oder verwendet werden könnte, fügen Sie den Code in ApplicationController ein.
  • Wenn der Code den Status benötigt und in einer Teilmenge aller Controller verwendet wird, die eng und logisch miteinander verbunden sind (dh alles über Maps), erstellen Sie eine Basisklasse ( class MapController < ApplicationController) und fügen Sie den gemeinsam genutzten Code dort ein.
  • Wenn der Code den Status benötigt und in einer Teilmenge aller Controller verwendet wird, die nicht sehr eng miteinander verbunden sind, fügen Sie ihn in ein Modul ein und fügen Sie ihn in die erforderlichen Controller ein.

In Ihrem Fall benötigen die Methoden state ( params), sodass die Auswahl von der logischen Beziehung zwischen den Controllern abhängt, die sie benötigen. Zusätzlich:

Ebenfalls:

  • Verwenden Sie Partials, wenn möglich, für wiederholten Code und platzieren Sie sie entweder in einem gemeinsamen 'Partials'-Verzeichnis oder über einen bestimmten Pfad.
  • Halten Sie sich nach Möglichkeit an einen RESTful-Ansatz (für Methoden), und wenn Sie feststellen, dass Sie viele nicht-RESTful-Methoden erstellen, sollten Sie diese auf ihren eigenen Controller extrahieren.
Ian Terrell
quelle
33

Ich weiß, dass diese Frage vor 6 Jahren gestellt wurde. Ich möchte nur darauf hinweisen, dass es in Rails 4 jetzt Controller-Bedenken gibt, die eine sofort einsatzbereite Lösung darstellen.

Sam G.
quelle
15

Ich denke tatsächlich, dass ein Modul der beste Weg ist, um Code zwischen Controllern zu teilen. Helfer sind gut, wenn Sie Code für Ansichten freigeben möchten. Helfer sind im Grunde verherrlichte Module. Wenn Sie also keinen Zugriff auf Ansichtsebene benötigen, empfehle ich, ein Modul in Ihrem lib-Ordner abzulegen.

Sobald Sie das Modul erstellt haben, müssen Sie die include-Anweisung verwenden, um es in die gewünschten Controller aufzunehmen.

http://www.rubyist.net/~slagell/ruby/modules.html

Danpickett
quelle
1

Ich stimme dem Modulansatz zu. Erstellen Sie eine separate Ruby-Datei in Ihrem lib-Verzeichnis und fügen Sie das Modul in die neue Datei ein.

Der naheliegendste Weg wäre, die Methoden zu Ihrem ApplicationController hinzuzufügen, aber ich bin sicher, dass Sie das bereits wissen.

Christoph Schiessl
quelle
1

Wenn Sie Codes zwischen Controller und Helfern freigeben möchten, sollten Sie versuchen, ein Modul in der Bibliothek zu erstellen. Sie können @template und @controller auch für den Zugriff auf Methoden in Controller und Helper verwenden. Überprüfen Sie dies für weitere Details http://www.shanison.com/?p=305

Shanison
quelle
0

Andere Möglichkeit:

Wenn Ihr allgemeiner Code den Status benötigt und Sie das Verhalten zwischen Controllern teilen möchten, können Sie ihn in eine einfache alte Ruby-Klasse in Ihrem modeloder Ihrem libVerzeichnis einfügen . Denken Sie daran, dass modelKlassen nicht persistent sein müssen, obwohl alle ActiveRecord-Klassen persistent sind. Mit anderen Worten, es ist akzeptabel, vorübergehende modelKlassen zu haben .

Alan
quelle
0

Ich fand heraus, dass eine effektive Möglichkeit, identischen Code zwischen Controllern zu teilen, darin besteht, einen Controller vom anderen zu erben (wo der Code lebt). Ich habe diesen Ansatz verwendet, um identische Methoden, die in meinen Controllern definiert sind, mit einem anderen Satz von Controllern mit Namespace zu teilen.

Daniel Bonnell
quelle
1
Die Verwendung der Vererbung zum Freigeben von Code wird als Codegeruch betrachtet. Sie sollten es vermeiden. Siehe programmers.stackexchange.com/a/12446 . Verwenden Sie stattdessen Module, Anliegen oder sogar Serviceobjekte .
Mio