Mejores prácticas para reutilizar código entre controladores en Ruby on Rails

82

Tengo algunos métodos de control que me gustaría compartir. ¿Cuál es la mejor práctica para hacer esto en ruby ​​on rails? ¿Debo crear una clase abstracta que amplíen mis controladores, o debo crear un módulo y agregarlo a cada controlador? A continuación se muestran los métodos del controlador que quiero compartir:

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
fuente
1
¿Hay alguna razón en particular para no usar application.rb en este caso?
PJ.
4
Solo que algunos controladores usarán el código, pero no todos.
Kyle Boon

Respuestas:

113

En mi opinión, se aplican los principios normales de diseño de OO:

  • Si el código es realmente un conjunto de utilidades que no necesita acceso al estado del objeto, consideraría ponerlo en un módulo para llamarlo por separado. Por ejemplo, si el código es todos los servicios de mapeo, crear un módulo Maps, y acceder a los métodos como: Maps::driving_directions.
  • Si el código necesita estado y se usa o podría usarse en todos los controladores, coloque el código en ApplicationController.
  • Si el código necesita estado y se usa en un subconjunto de todos los controladores que están estrecha y lógicamente relacionados (es decir, todo sobre mapas), entonces cree una clase base ( class MapController < ApplicationController) y coloque el código compartido allí.
  • Si el código necesita estado y se usa en un subconjunto de todos los controladores que no están muy relacionados, colóquelo en un módulo e inclúyalo en los controladores necesarios.

En su caso, los métodos necesitan state ( params), por lo que la elección depende de la relación lógica entre los controladores que lo necesitan. Adicionalmente:

También:

  • Utilice parciales cuando sea posible para el código repetido y colóquelo en un directorio común de 'parciales' o incluya a través de una ruta específica.
  • Apéguese a un enfoque RESTful cuando sea posible (para métodos) y si se encuentra creando muchos métodos no RESTful, considere extraerlos a su propio controlador.
Ian Terrell
fuente
33

Sé que esta pregunta se hizo hace 6 años. Solo quiero señalar que en Rails 4, ahora hay problemas de controlador que son una solución más lista para usar.

Sam G
fuente
16

De hecho, creo que un módulo es la mejor manera de compartir código entre controladores. Los ayudantes son buenos si desea compartir código entre vistas. Los ayudantes son básicamente módulos glorificados, por lo que si no necesita acceso a nivel de vista, le sugiero que coloque un módulo en su carpeta lib.

Una vez que cree el módulo, tendrá que usar la declaración de inclusión para incluirlo en los controladores deseados.

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

danpickett
fuente
1

Estoy de acuerdo con el enfoque del módulo. Cree un archivo Ruby separado en su directorio lib y coloque el módulo en el nuevo archivo.

La forma más obvia sería agregar los métodos a su ApplicationController, pero estoy seguro de que ya lo sabe.

Christoph Schiessl
fuente
1

Si desea compartir códigos entre el controlador y los ayudantes, debería intentar crear un módulo en la biblioteca. También puede usar @template y @controller para acceder al método en el controlador y el ayudante. Consulte esto para obtener más detalles http://www.shanison.com/?p=305

Shanison
fuente
0

Otra posibilidad:

Si su código común necesita un estado y desea compartir el comportamiento entre los controladores, puede ponerlo en una vieja clase ruby ​​en su directorio modelo lib. Recuerde que las modelclases no tienen que ser persistentes aunque todas las clases de ActiveRecord sean persistentes. En otras palabras, es aceptable tener modelclases transitorias .

Alan
fuente
0

Descubrí que una forma efectiva de compartir código idéntico entre controladores es hacer que un controlador herede del otro (donde vive el código). Utilicé este enfoque para compartir métodos idénticos definidos en mis controladores con otro conjunto de controladores con espacio de nombres.

Daniel Bonnell
fuente
1
El uso de la herencia para compartir código se considera un olor a código. Deberías evitarlo. Consulte programmers.stackexchange.com/a/12446 . Utilice en su lugar módulos, inquietudes o incluso objeto de servicios .
Mio