Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何在gem中扩展ApplicationController?_Ruby On Rails_Ruby On Rails 3_Gem_Applicationcontroller_Load Order - Fatal编程技术网

Ruby on rails 如何在gem中扩展ApplicationController?

Ruby on rails 如何在gem中扩展ApplicationController?,ruby-on-rails,ruby-on-rails-3,gem,applicationcontroller,load-order,Ruby On Rails,Ruby On Rails 3,Gem,Applicationcontroller,Load Order,我想我会想出一个巧妙的方法来扩展Rails3.xGem中的ApplicationController 在我的gem的lib/my_namespace/my_controller.rb中,我有: class MyNamespace::MyController < ApplicationController before_filter :some_method after_filter :another_method def initialize # getting c

我想我会想出一个巧妙的方法来扩展Rails3.xGem中的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
作为一种解决方法,我在gem的
lib/gem\u名称空间/application\u controller.rb
中将ApplicationController定义为:

class ApplicationController < ActionController::Base
end
lib/your\u gem\u name/controller.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
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

对于这种特定的功能,我建议在gem中创建一个模块,并将该模块包括在应用程序控制器中

class ApplicationController < ActionController::Base
  include MyCoolModule
end
class SpecialCaseController < GemApplicationController
  # this will inherit from the gem's controller, 
  # which inherits from the rails_app ApplicationController
end
更新:你可能只需要做
base.before\u filter:my\u method
,它更干净。


这显示了如何访问子类的类并将其存储在实例变量中,以及如何在before和after过滤器中访问它。它使用include方法

我能够通过初始化器回调引用ApplicationController

子类化/引用ApplicationController的gem代码:

class GemApplicationController < ApplicationController
  before_filter :method_to_call

  def method_to_call
    #your code here
  end
end
module GemName
  def self.load_gem_application_controller
    require "path/to/gem_application_controller"
  end
end
rails_app/config/initializers/gem_name.rb

GemName.load_gem_application_controller
然后让使用此功能的控制器子类GemApplicationController

class ApplicationController < ActionController::Base
  include MyCoolModule
end
class SpecialCaseController < GemApplicationController
  # this will inherit from the gem's controller, 
  # which inherits from the rails_app ApplicationController
end
class SpecialCaseController
真相更简单、更灵活

添加到
lib/engine.rb
this:
classengine

然后简单地使用:

ActionController::Base.class_eval do

  include SomethingFromMineGemModule

  # or:
  def hello_from_gem
    'Hey people!'
  end

end

在这种情况下,包含模块真的有效吗?既然没有子类,您能否详细介绍一下如何获得子类的名称,以及如何利用prefore\u filter和after\u filter?再看一看这个问题,如果你能进一步阐述,请澄清。否则,我认为这不是一个选项。谢谢刚才在问题的最后一行澄清了我需要使用before\u filter、after\u filter和访问子类的名称。太棒了!那么,包括一个模块真的是最好的主意。非常感谢你的帮助!我了解到使用模块更好。您只能(直接)从一个父类继承,但您可以根据需要包括/扩展模块。谢谢Gary。我最终也实现了一个模块。