问题描述
在我的gem的 lib中,我想到了一个简单的方法来将ApplicationController扩展到Rails 3.x gem。 /my_namespace/my_controller.rb ,我有:
class MyNamespace :: MyController< ApplicationController
before_filter:some_method
after_filter:another_method
def初始化
#获取用于查找关联模型的子类的类名等。
#并将model_class存储在实例变量
#...
end
#define:some_method,:another_method等
#中。 ..
私人
attr_accessor:subclass_defined_during_initialize#等
#等
最终
但是当Gem被加载时, app / controllers / application_controller.rb 尚未加载,所以它失败:
/path/to/rvm/gemset/gems/activesupport-3.2.6/lib/active_support/dependencies.rb :251:b $ b在`require'中:无法加载这样的文件 - my_gem_name / application_controller(LoadError)
作为一种解决方法,我已将ApplicationController定义在我的gem的 lib / gem_namespace / application_controller.rb $ c $中c> as:
class ApplicationController< ActionController :: Base
end
我认为即使我已经定义了它,将在我的Rails 3应用程序的 app / controllers / application_controller.rb 中重新定义,这样应用程序中的两个控制器扩展了 ApplicationController 和扩展 MyNamespace :: MyController 的控制器将直接或间接地扩展在 app / controllers / application_controller.rb $ c $中定义的ApplicationController然而,我们注意到在加载gem之后,扩展 ApplicationController 的控制器无法访问方法在 app / controllers / application_controller.rb 中定义。此外, ApplicationHelper (app / helpers / application_helper.rb)模块不再由其他helper模块加载。
如何在我的gem控制器中扩展 ApplicationController ,以定义 before_filter 和 after_filter 并使用 initialize 来访问类的名称以确定关联模型的类,它可以在其方法中存储和使用它?
Update 2012/10/22 :
下面是我想到的:
在 lib / your_gem_name / railtie.rb :
模块YourGemsModuleName
class Railtie< Rails :: Railtie
初始化器your_gem_name.action_controllerdo
ActiveSupport.on_load(:action_controller)do
将扩展#{self}与YourGemsModuleName :: Controller
#ActionController :: Base获取一个允许控制器包含新行为的方法
包含YourGemsModuleName :: Controller#ActiveSupport :: Concern
end
end
end
和 lib / your_gem_name / controller.rb :
模块YourGemsModuleName
模块控制器
扩展ActiveSupport ::关注
#注意:不要指定包含的或ClassMethods(如果未使用)
包含做
#任何您想在每个控制器中执行的操作,例如:添加类属性
class_attribute:class_attribute_available_on_every_controller,instance_writer:false
结束
模块ClassMethods
#notice:no self.method_name这是因为ActiveSupport :: Concern被扩展
def make_this_controller_fantastic
before_filter:some_instance_method_available_on_every_controller#在每个控制器上都可用
after_filter:another_instance_method_available_on_every_controller#在每个控制器上都可用
包含FantasticStuff
end
end
#每个控制器上的实例方法转到这里
def some_instance_method_available_on_every_controller
puts每种控制器上都有可用的方法!
结束
def another_instance_method_available_on_every_controller
提供另一种方法可用于每个控制器!
end
模块FantasticStuff
扩展ActiveSupport :: Concern
#注意:如果未使用,不要指定包含或ClassMethods
包含做
class_attribute:class_attribute_only_available_on_fantastic_controllers,instance_writer:false
结束
模块ClassMethods
#只有在控制器中指定了make_this_controller_fantastic时才可用的类方法
def some_fanastic_class_method
把一个梦幻般的课程方法!
end
end
#实例方法只有在控制器中指定了make_this_controller_fantastic时才可用
def some_fantastic_instance_method
提供一个奇妙的实例方法!
结束
def another_fantastic_instance_method
提供另一个绝妙的实例方法!
end
end
end
end
,显示如何访问类的子类并将其存储在实例变量中,并在前后过滤器中访问它。它使用包含方法。
I thought I'd come up with a slick way to extend ApplicationController in a Rails 3.x gem.
In my gem's lib/my_namespace/my_controller.rb, I had:
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
but when the Gem is loaded, app/controllers/application_controller.rb is not yet loaded, so it fails:
/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)
As a workaround, I had defined ApplicationController in my gem's lib/gem_namespace/application_controller.rb as:
class ApplicationController < ActionController::Base end
I assumed that even though I had defined it there, it would be redefined in my Rails 3 application's app/controllers/application_controller.rb, such that both controllers in the application that extended ApplicationController and controllers that extended MyNamespace::MyController would directly or indirectly extend the ApplicationController defined in app/controllers/application_controller.rb.
However, we noticed that after loading the gem, controllers that extend ApplicationController were unable to access methods defined in app/controllers/application_controller.rb. Also, the ApplicationHelper (app/helpers/application_helper.rb) module was no longer being loaded by other helper modules.
How can I extend ApplicationController within the controller in my gem for the purpose of defining a before_filter and after_filter to and use initialize to access the class's name to determine the associated model's class that it could then store and use within its methods?
Update 2012/10/22:
Here's what I came up with:
In 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
and in lib/your_gem_name/controller.rb:
module YourGemsModuleName module Controller extend ActiveSupport::Concern # note: don't specify included or ClassMethods if unused included do # anything you would want to do in every controller, for example: add a class attribute class_attribute :class_attribute_available_on_every_controller, instance_writer: false end module ClassMethods # notice: no self.method_name here, because this is being extended because ActiveSupport::Concern was extended def make_this_controller_fantastic before_filter :some_instance_method_available_on_every_controller # to be available on every controller after_filter :another_instance_method_available_on_every_controller # to be available on every controller include FantasticStuff end end # instance methods to go on every controller go here def some_instance_method_available_on_every_controller puts "a method available on every controller!" end def another_instance_method_available_on_every_controller puts "another method available on every controller!" end module FantasticStuff extend ActiveSupport::Concern # note: don't specify included or ClassMethods if unused included do class_attribute :class_attribute_only_available_on_fantastic_controllers, instance_writer: false end module ClassMethods # class methods available only if make_this_controller_fantastic is specified in the controller def some_fanastic_class_method put "a fantastic class method!" end end # instance methods available only if make_this_controller_fantastic is specified in the controller def some_fantastic_instance_method puts "a fantastic instance method!" end def another_fantastic_instance_method puts "another fantastic instance method!" end end end end
Here is a Gistthat shows how to access the class of the subclass and store it in an instance variable and access it in the before and after filters. It uses the include method.
这篇关于我如何将ApplicationController扩展到gem中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!