Лучшие практики для повторного использования кода между контроллерами в Ruby on Rails

82

У меня есть несколько методов контроллера, которыми я хотел бы поделиться. Как лучше всего это сделать в Ruby on Rails? Должен ли я создать абстрактный класс, который расширяют мои контроллеры, или мне следует создать модуль и добавить его к каждому контроллеру? Ниже приведены методы контроллера, которыми я хочу поделиться:

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
Кайл Бун
источник
1
Есть ли конкретная причина не использовать application.rb в этом случае?
PJ.
4
Только то, что некоторые контроллеры будут использовать код, но не все.
Кайл Бун,

Ответы:

113

На мой взгляд, применимы обычные принципы объектно-ориентированного проектирования:

  • Если код действительно представляет собой набор утилит, которым не нужен доступ к состоянию объекта, я бы подумал о том, чтобы поместить его в модуль, который будет вызываться отдельно. Например, если код представляет собой все утилиты сопоставления, создайте модуль Mapsи получите доступ к таким методам, как: Maps::driving_directions .
  • Если код требует состояния и используется или может использоваться в каждом контроллере, поместите код в ApplicationController.
  • Если код требует состояния и используется в подмножестве всех контроллеров, которые тесно и логически связаны (то есть все о картах), тогда создайте базовый класс ( class MapController < ApplicationController) и поместите туда общий код.
  • Если код требует состояния и используется в подмножестве всех контроллеров, которые не очень тесно связаны между собой, поместите его в модуль и включите в необходимые контроллеры.

В вашем случае методам требуется state ( params), поэтому выбор зависит от логической взаимосвязи между контроллерами, которым это нужно. К тому же:

Также:

  • По возможности используйте частичные данные для повторяющегося кода и либо поместите их в общий каталог «частичных», либо включите по определенному пути.
  • По возможности придерживайтесь подхода RESTful (для методов), и если вы обнаружите, что создаете много методов, не относящихся к RESTful, подумайте о том, чтобы извлечь их в собственный контроллер.
Ян Террелл
источник
33

Я знаю, что этот вопрос задавали 6 лет назад. Просто хочу отметить, что в Rails 4 теперь есть проблемы с контроллерами, которые являются более нестандартным решением.

Сэм Джи
источник
16

На самом деле я думаю, что модуль - лучший способ поделиться кодом между контроллерами. Помощники хороши, если вы хотите поделиться кодом между представлениями. Помощники - это в основном прославленные модули, поэтому, если вам не нужен доступ на уровне просмотра, я предлагаю разместить модуль в папке lib.

После создания модуля вам нужно будет использовать оператор include, чтобы включить его в нужные контроллеры.

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

Дэнпикетт
источник
1

Я согласен с модульным подходом. Создайте отдельный файл Ruby в каталоге lib и поместите модуль в новый файл.

Наиболее очевидным способом было бы добавить методы в ваш ApplicationController, но я уверен, что вы это уже знаете.

Кристоф Шиссль
источник
1

если вы хотите обмениваться кодами между контроллером и помощниками, вам следует попробовать создать модуль в библиотеке. Вы также можете использовать @template и @controller для доступа к методу в контроллере и помощнике. Проверьте это для получения дополнительной информации http://www.shanison.com/?p=305

Шенисон
источник
0

Другая возможность:

Если вашему общему коду требуется состояние, и вы хотите поделиться поведением между контроллерами, вы можете поместить его в простой старый класс ruby ​​в вашем каталоге modelили lib. Помните, что modelклассы не обязательно должны быть постоянными, даже если все классы ActiveRecord являются постоянными. Другими словами, допустимы переходные modelклассы.

Алан
источник
0

Я обнаружил, что один из эффективных способов совместного использования идентичного кода между контроллерами - это наследование одного контроллера от другого (где находится код). Я использовал этот подход для совместного использования идентичных методов, определенных в моих контроллерах, с другим набором контроллеров с пространством имен.

Дэниел Боннелл
источник
1
Использование наследования для совместного использования кода рассматривается как запах кода. Вам следует избегать этого. См. Programmers.stackexchange.com/a/12446 . Вместо этого используйте модули, проблемы или даже объекты услуг .
Mio