Движок Rails 3.0 — выполнение кода в ActionController

Я обновляю свой плагин Rails, чтобы он работал с последней версией 3.0RC1, и у меня возникли проблемы с поиском лучшего (и наиболее правильного) способа расширения ActionController. Я видел этот пост от DHH и этот вопрос здесь, на SO, но мой вопрос больше о том, как правильно вызывать код в ActionController.

Например, мне нужно вызвать в контроллере моего движка следующее:

class ApplicationController < ActionController::Base
  helper :all

  before_filter :require_one_user
  after_filter :store_location

  private
    def require_one_user
      # Code goes here
    end

    def store_location
      # Code goes here
    end
end

Я знаю, как правильно включить две мои частные функции, но я не могу найти способ заставить его правильно вызывать helper, before_filter и after_filter.

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


person Topher Fangio    schedule 12.08.2010    source источник


Ответы (2)


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

Вот что я использовал:


module MyEngine  
  class Engine < Rails::Engine  
    initializer 'my_engine.helper' do |app|  
      ActionView::Base.send :include, MyEngineHelper  
    end  

    initializer 'my_engine.controller' do |app|  
      ActiveSupport.on_load(:action_controller) do  
         include MyEngineActionControllerExtension  
      end
    end
  end
end

Кроме того, еще одним вариантом расширения контроллера действий является использование модуля миксина. Это позволит вам использовать before_filter, after_filter и т. д.


module MyEngineActionControllerExtension
  def self.included(base)
    base.send(:include, InstanceMethods) 
    base.before_filter :my_method_1
    base.after_filter :my_method_2
  end

  module InstanceMethods
   #...........
  end
end

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

/myengine/app/helpers/myengine_application_helper_extension.rb
/myengine/app/controllers/my_engine_action_controller_extension.rb

Мне нравится эта установка, потому что она похожа на application_controller и application_helper в вашем приложении rails. Опять же, это просто личное предпочтение, но я стараюсь хранить все, что напрямую связано с рельсами, например, контроллеры, помощники и модели внутри /my_engine/app и все, что связано с плагином в целом, внутри /my_engine/lib

Ознакомьтесь с этим руководством Хосе Валима для получения дополнительной информации об инициализаторах: https://gist.github.com/e139fa787aa882c0aa9c (engine_name сейчас устарело, но большая часть этого документа кажется актуальной)

person johnmcaliley    schedule 16.08.2010
comment
+1 и принято - спасибо за эту замечательную статью! Я ценю, что вы нашли время, хотя я уже ответил на него сам. Приятно видеть более элегантное решение. О, и добро пожаловать в Stack Overflow :-) - person Topher Fangio; 16.08.2010

Итак, я, наконец, понял решение, и я надеюсь, что это поможет кому-то еще.

Вам нужно создать файл в каталоге lib, потому что вы фактически собираетесь расширить класс. Я сделал myplugin/lib/extensions/action_controller_base.rb.

Затем внутри вашего файла myplugin/lib/myplugin.rb сделайте следующее:

require 'extensions/action_controller_base.rb'

Внутри myplugin/lib/extensions/action_controller_base.rb поместите следующее:

require 'action_controller'  # Make sure ActionController::Base is defined

ActionController::Base.class_eval {
  private
    def my_method_1
      # Code Goes Here
    end

    def my_method_2
      # Code Goes Here
    end
}

ActionController::Base.instance_eval {
  helper_method :my_method_1, :my_method_2

  before_filter :my_method_1
  after_filter :my_method_2
}

Если вам нужны хелперы представления, создайте их в каталоге myplugin/lib/helpers (или где-нибудь внутри lib, имя «помощники» не имеет значения) и добавьте следующее в конец myplugin/lib/extensions/action_controller_base.rb:

require 'helpers/helper_file_1'
require 'helpers/helper_file_2'

ActionView::Base.send :include, MyHelper1
ActionView::Base.send :include, MyHelper2
person Topher Fangio    schedule 14.08.2010