我怎样才能在创业板延伸的ApplicationController?(How can I exten

2019-06-26 02:09发布

我以为我会拿出一个漂亮的方式在Rails 3.x的宝石延伸的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

但加载宝石时, 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

我认为即使我已经有定义它,它会在我的Rails 3重新定义应用程序的app/controllers/application_controller.rb ,使得该扩展应用两个控制器ApplicationController和扩展控制器MyNamespace::MyController将直接或间接地延伸所限定的ApplicationController中app/controllers/application_controller.rb

然而,我们注意到,在加载后的宝石,扩展控制器ApplicationController无法访问定义的方法app/controllers/application_controller.rb 。 此外, ApplicationHelper (app/helpers/application_helper.rb)模块不再被其他辅助模块加载。

我怎样才能延长ApplicationController控制器内我的创业板定义的目的before_filterafter_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

Answer 1:

这里是一个要点 ,显示了如何访问类的子类,并将其存储在一个实例变量和访问它在之前和之后的过滤器。 它采用了包括方法。



Answer 2:

对于这种特定种类的功能,我建议建立在你的宝石模块和包括该模块在你的应用程序控制器

class ApplicationController < ActionController::Base
  include MyCoolModule
end

要过滤器之前添加等(添加到您的模块)

def self.included(base)
  base.send(:before_filter, my_method)
end

更新:你可以只是做base.before_filter :my_method这是清洁。



Answer 3:

事实是很多更简单,灵活。

添加到lib/engine.rb这样的: class Engine < Rails::Engine; end class Engine < Rails::Engine; end

然后只需使用:

ActionController::Base.class_eval do

  include SomethingFromMineGemModule

  # or:
  def hello_from_gem
    'Hey people!'
  end

end


Answer 4:

我能有一个初始化的回调引用ApplicationController中。

创业板代码,子类/引用的ApplicationController:

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 /配置/初始化/ 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


文章来源: How can I extend ApplicationController in a gem?