title: How can I extend ApplicationController in a gem?
body: <p>I thought I'd come up with a slick way to extend ApplicationController in a Rails 3.x gem.</p>
  
  <p>In my gem's <code>lib/my_namespace/my_controller.rb</code>, I had:</p>
  
  <pre><code>class MyNamespace::MyController &lt; 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
  </code></pre>
  
  <p>but when the Gem is loaded, <code>app/controllers/application_controller.rb</code> is not yet loaded, so it fails:</p>
  
  <pre><code>/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)
  </code></pre>
  
  <p>As a workaround, I had defined ApplicationController in my gem's <code>lib/gem_namespace/application_controller.rb</code> as:</p>
  
  <pre><code>class ApplicationController &lt; ActionController::Base
  end
  </code></pre>
  
  <p>I assumed that even though I had defined it there, it would be redefined in my Rails 3 application's <code>app/controllers/application_controller.rb</code>, such that both controllers in the application that extended <code>ApplicationController</code> and controllers that extended <code>MyNamespace::MyController</code> would directly or indirectly extend the ApplicationController defined in <code>app/controllers/application_controller.rb</code>.</p>
  
  <p>However, we noticed that after loading the gem, controllers that extend <code>ApplicationController</code> were unable to access methods defined in <code>app/controllers/application_controller.rb</code>. Also, the <code>ApplicationHelper</code> <code>(app/helpers/application_helper.rb)</code> module was no longer being loaded by other helper modules.</p>
  
  <p>How can I extend <code>ApplicationController</code> within the controller in my gem for the purpose of defining a <code>before_filter</code> and <code>after_filter</code> to and use <code>initialize</code> to access the class's name to determine the associated model's class that it could then store and use within its methods?</p>
  
  <p><em>Update 2012/10/22</em>:</p>
  
  <p>Here's what I came up with:</p>
  
  <p>In <code>lib/your_gem_name/railtie.rb</code>:</p>
  
  <pre><code>module YourGemsModuleName
    class Railtie &lt; 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
  </code></pre>
  
  <p>and in <code>lib/your_gem_name/controller.rb</code>:</p>
  
  <pre><code>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
  </code></pre>