我想我會想出一個在Rails 3.x gem中擴展ApplicationController的方法。如何將ApplicationController擴展到gem中?
在我家創業板公司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
但加載寶石時,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)
作爲一種解決辦法,我已經確定ApplicationController中我的寶石的lib/gem_namespace/application_controller.rb
爲:
class ApplicationController < ActionController::Base
end
I假定即使我已經在那裏定義了它,它將在我的Rails 3應用程序的app/controllers/application_controller.rb
中被重新定義,使得應用程序中擴展了ApplicationController
的控制器和擴展MyNamespace::MyController
的控制器將直接或間接地擴展app/controllers/application_controller.rb
中定義的ApplicationController。
但是,我們注意到在加載gem後,擴展爲ApplicationController
的控制器無法訪問在app/controllers/application_controller.rb
中定義的方法。另外,ApplicationHelper
(app/helpers/application_helper.rb)
模塊不再由其他輔助模塊加載。
我怎麼能在我的寶石控制器內延長ApplicationController
用於定義before_filter
和after_filter
並使用initialize
訪問類的名稱,以確定相關模型的類,它可能然後存儲及其方法中使用的目的是什麼?
更新2012年10:
這就是我想出了:
在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
:
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
太棒了!那麼包括一個模塊真的是最好的主意。非常感謝你的幫助! – 2012-07-06 12:48:29
[Rails論壇中的相關對話](https://web.archive.org/web/20130216193936/http://railsforum.com/viewtopic.php?pid=153813) – 2012-07-06 13:15:55