Najlepsze praktyki dotyczące ponownego wykorzystywania kodu między kontrolerami w Ruby on Rails

82

Mam kilka metod kontrolera, którymi chciałbym się podzielić. Jaka jest najlepsza praktyka, aby to zrobić w Ruby on Rails? Czy powinienem utworzyć klasę abstrakcyjną, którą rozszerzają moje kontrolery, czy powinienem utworzyć moduł i dodać go do każdego kontrolera? Poniżej znajdują się metody kontrolera, które chcę udostępnić:

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
źródło
1
Czy jest jakiś konkretny powód, dla którego nie należy używać application.rb w tym przypadku?
PJ.
4
Tyle tylko, że część kontrolerów użyje kodu, ale nie wszystkie.
Kyle Boon,

Odpowiedzi:

113

Moim zdaniem obowiązują normalne zasady projektowania obiektowego:

  • Jeśli kod jest naprawdę zestawem narzędzi, który nie potrzebuje dostępu do stanu obiektu, rozważałbym umieszczenie go w module, który będzie wywoływany osobno. Na przykład, jeśli kod składa się z narzędzi do mapowania, utwórz moduł Mapsi uzyskaj dostęp do metod takich jak: Maps::driving_directions .
  • Jeśli kod wymaga stanu i jest używany lub może być używany w każdym kontrolerze, umieść kod w ApplicationController.
  • Jeśli kod wymaga stanu i jest używany w podzbiorze wszystkich kontrolerów, które są blisko i logicznie powiązane (tj. Wszystkie dotyczące map), utwórz klasę bazową ( class MapController < ApplicationController) i umieść tam wspólny kod.
  • Jeśli kod wymaga stanu i jest używany w podzbiorze wszystkich kontrolerów, które nie są zbyt blisko spokrewnione, umieść go w module i dołącz do niezbędnych kontrolerów.

W twoim przypadku metody wymagają state ( params), więc wybór zależy od logicznej relacji między kontrolerami, które tego potrzebują. Dodatkowo:

Również:

  • Jeśli to możliwe, używaj części składowych dla powtarzanego kodu i albo umieść je w wspólnym katalogu „częściowe”, albo dołącz za pomocą określonej ścieżki.
  • W miarę możliwości trzymaj się podejścia RESTful (w przypadku metod), a jeśli tworzysz wiele metod innych niż RESTful, rozważ wyodrębnienie ich do własnego kontrolera.
Ian Terrell
źródło
33

Wiem, że to pytanie zostało zadane 6 lat temu. Chcę tylko zaznaczyć, że w Railsach 4 są teraz problemy z kontrolerami, które są bardziej nieszablonowym rozwiązaniem.

Sam G
źródło
16

Właściwie myślę, że moduł to najlepszy sposób na udostępnianie kodu kontrolerom. Pomocnicy są dobrzy, jeśli chcesz udostępniać kod między widokami. Helpery to w zasadzie gloryfikowane moduły, więc jeśli nie potrzebujesz dostępu do poziomu widoku, sugeruję umieszczenie modułu w folderze lib.

Po utworzeniu modułu będziesz musiał użyć instrukcji include, aby dołączyć go do żądanych kontrolerów.

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

danpickett
źródło
1

Zgadzam się z podejściem modułowym. Utwórz osobny plik Ruby w swoim katalogu lib i umieść moduł w nowym pliku.

Najbardziej oczywistym sposobem byłoby dodanie metod do ApplicationController, ale jestem pewien, że już to wiesz.

Christoph Schiessl
źródło
1

jeśli chcesz udostępniać kody między kontrolerem a pomocnikami, powinieneś spróbować utworzyć moduł w bibliotece. Możesz użyć @template i @controller, aby uzyskać dostęp do metody w kontrolerze i pomocniku. Sprawdź to, aby uzyskać więcej informacji http://www.shanison.com/?p=305

Shanison
źródło
0

Inna możliwość:

Jeśli twój wspólny kod wymaga stanu i chcesz podzielić zachowanie między kontrolerami, możesz umieścić go w zwykłej starej klasie ruby ​​w swoim katalogu modellub lib. Pamiętaj, że modelklasy nie muszą być trwałe, mimo że wszystkie klasy ActiveRecord są trwałe. Innymi słowy, dopuszczalne są modelklasy przejściowe .

Alan
źródło
0

Odkryłem, że skutecznym sposobem udostępniania identycznego kodu między kontrolerami jest posiadanie jednego kontrolera dziedziczącego po drugim (gdzie kod żyje). Użyłem tego podejścia, aby udostępnić identyczne metody zdefiniowane w moich kontrolerach z innym zestawem kontrolerów w przestrzeni nazw.

Daniel Bonnell
źródło
1
Używanie dziedziczenia do udostępniania kodu jest uważane za zapach kodu. Powinieneś tego unikać. Zobacz programmers.stackexchange.com/a/12446 . Zamiast tego użyj modułów, problemów lub nawet obiektu usług .
Mio