我以为我想出了一个灵活的方法来扩展Rails 3.x gem中的ApplicationController。
在我的宝石lib/my_namespace/my_controller.rb
中,我有:
class MyNamespace::MyController < ApplicationController
before_filter :some_method
after_filter :another_method
def initialize
# getting classname of the subclass to use for lookup of the associated model, etc.
# and storing the model_class in an instance variable
# ...
end
# define :some_method, :another_method, etc.
# ...
private
attr_accessor :subclass_defined_during_initialize # etc.
# etc.
end
但是当加载Gem时,app/controllers/application_controller.rb
尚未加载,因此失败:
/path/to/rvm/gemset/gems/activesupport-3.2.6/lib/active_support/dependencies.rb:251:
in `require': cannot load such file -- my_gem_name/application_controller (LoadError)
作为一种解决方法,我在我的gem lib/gem_namespace/application_controller.rb
中定义了ApplicationController:
class ApplicationController < ActionController::Base
end
我认为即使我在那里定义了它,它也会在我的Rails 3应用程序的app/controllers/application_controller.rb
中重新定义,这样应用程序中的两个控制器都扩展了ApplicationController
和控制器扩展了{{1}将直接或间接扩展MyNamespace::MyController
中定义的ApplicationController。
但是,我们注意到在加载gem之后,扩展app/controllers/application_controller.rb
的控制器无法访问ApplicationController
中定义的方法。此外,其他帮助程序模块不再加载app/controllers/application_controller.rb
ApplicationHelper
模块。
如何在我的gem中的控制器中扩展(app/helpers/application_helper.rb)
,以便定义ApplicationController
和before_filter
并使用after_filter
来访问类的名称以确定相关模型的类,它可以在其方法中存储和使用?
更新2012/10/22 :
以下是我提出的建议:
在initialize
:
lib/your_gem_name/railtie.rb
和module YourGemsModuleName
class Railtie < Rails::Railtie
initializer "your_gem_name.action_controller" do
ActiveSupport.on_load(:action_controller) do
puts "Extending #{self} with YourGemsModuleName::Controller"
# ActionController::Base gets a method that allows controllers to include the new behavior
include YourGemsModuleName::Controller # ActiveSupport::Concern
end
end
end
:
lib/your_gem_name/controller.rb
答案 0 :(得分:8)
对于这种特定类型的功能,我建议在gem中创建一个模块,并在应用程序控制器中包含该模块
class ApplicationController < ActionController::Base
include MyCoolModule
end
要在过滤器之前添加等(将其添加到您的模块中)
def self.included(base)
base.send(:before_filter, my_method)
end
更新:你可能只能做一个更清洁的base.before_filter :my_method
。
答案 1 :(得分:5)
Here is a Gist 它显示了如何访问子类的类并将其存储在实例变量中,并在前后过滤器中访问它。它使用include方法。
答案 2 :(得分:2)
真理更加简单灵活。
添加到lib/engine.rb
这个:class Engine < Rails::Engine; end
然后简单地使用:
ActionController::Base.class_eval do
include SomethingFromMineGemModule
# or:
def hello_from_gem
'Hey people!'
end
end
答案 3 :(得分:0)
我能够使用初始化程序回调引用ApplicationController。
子类/引用ApplicationController的gem代码:
class GemApplicationController < ApplicationController
before_filter :method_to_call
def method_to_call
#your code here
end
end
gem代码回调创建子类控制器:
module GemName
def self.load_gem_application_controller
require "path/to/gem_application_controller"
end
end
rails_app /配置/初始化/ gem_name.rb
GemName.load_gem_application_controller
然后让控制器使用此功能子类GemApplicationController
class SpecialCaseController < GemApplicationController
# this will inherit from the gem's controller,
# which inherits from the rails_app ApplicationController
end