Rails 3 — как организовать/разделить раздутые контроллеры?

Я работаю над приложением CMS, чтобы отточить свои навыки, и контроллеры становятся довольно раздутыми с определениями. Я знаю, что можно хранить вещи в lib/whatever.rb, а затем использовать require и include, но это не совсем работает с контроллерами — по крайней мере, в моем случае, где у меня есть before_filters. Без определений прямо в контроллере before_filters отказываются работать.

Все дефы ДОЛЖНЫ быть в контроллере или есть способ их убрать? (Они специфичны для этого контроллера, поэтому их нельзя использовать в контроллере приложений.


person dsp_099    schedule 07.06.2011    source источник
comment
вы можете создать контроллер с факторизованным before_filter и наследовать от него ваши контроллеры.   -  person apneadiving    schedule 08.06.2011
comment
Не могли бы вы конкретизировать свой вопрос, приведя несколько примеров? Во многих случаях, когда я видел, что эта проблема поднимается, логика вообще не должна была быть в контроллерах (а скорее в моделях или других классах).   -  person molf    schedule 08.06.2011
comment
Вам может быть полезно загрузить этот гем и прочитать исходный код, чтобы лучше понять экосистему контроллера: rubydoc.info/gems/inherited_resources/1.2.2/frames   -  person Tim Snowhite    schedule 08.06.2011


Ответы (2)


Вы можете делать много вещей с модулями примесей, которые добавят поведение к существующему контроллеру, или вы можете попытаться придумать иерархию классов, которая позволит контроллерам наследовать необходимые методы от своего родительского класса.

В большинстве приложений я создаю подкласс ApplicationController по крайней мере один раз, чтобы обеспечить соблюдение некоторых стандартов в определенных контекстах. Например, все контроллеры, относящиеся к проекту, будут наследоваться от ProjectController::Base:

class ProjectController::Base < ApplicationController
  before_filter :must_be_logged_in
  before_filter :load_project

protected
  def load_project
    @project = Project.find(params[:project_id] || params[:id])

  rescue ActiveRecord::RecordNotFound
    render(:template => 'not_found')
  end

  def must_be_logged_in
    # ...
  end
end
person tadman    schedule 07.06.2011
comment
Итак, у вас есть файл с именем ProjectController под контроллерами? - person dsp_099; 08.06.2011
comment
Каталог с именем project_controller с base.rb и несколькими производными классами в нем, каждый из которых обычно относится к определенному типу ресурса. ProjectController на самом деле наследуется от ProjectController::Base и имеет несколько настроек skip_before_filter, чтобы избежать попыток загрузки проектов, например, на index, new или create. - person tadman; 08.06.2011

плагин расширения (это скорее фрагмент) может быть решением для вас.

Что он делает (добавляет несколько методов в Object/Module)

class ::Object
  def self.augment(*mods)
    include *mods
    mods.each {|mod| class_eval &mod.augmentation }
  end
end

class ::Module
  def augmentation(&block)
    @augmentation ||= block
  end
end

Что он позволяет делать

# app/controllers/your_controller.rb
class YourController
  augment YourController::Stuff

  ...
end

# app/controllers/your_controller/stuff.rb
module YourController::Stuff
  augmentation do
    before_filter :something

    def something
      ...
    end
  end
end

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

person Marcel Jackwerth    schedule 07.06.2011
comment
Rails 3 запекает этот шаблон прямо с ActiveSupport::Concern и included do ... end. - person molf; 08.06.2011
comment
Черт, я забыл об этом - слишком много работал над устаревшими приложениями Rails 2.3. - person Marcel Jackwerth; 08.06.2011