0

I want to add a filter to the ApplicationController but I want to do it within my gem.

What I want to avoid is the following:

class ApplicationController < ActionController::Base
  include MyGem
end

I do not want that. I don't want to have to include my module in the source code.

I am having issues though.

Here is the relevant code:

lib/correlation_id/controller_extension

module CorrelationId
  module ControllerExtension

    def self.included(klass)
      klass.class_eval do
        after_filter :pass_correlation_id
      end
    end

    def pass_correlation_id
      correlation_id = request.headers['Correlation-ID'] || SecureRandom.uuid
      headers['Correlation-ID'] = correlation_id
    end
  end
end

ApplicationController.send :include, CorrelationId::ControllerExtension

lib/correlation_id.rb

require 'correlation_id/controller_extension'

module CorrelationId
end

Now, when I'm in the test/dummy directory, which is a test rails app for my gem, I try to boot up the server using rails s and I get the following error:

/correlation_id/lib/correlation_id/controller_extension.rb:17:in `<top (required)>': uninitialized constant ApplicationController (NameError)

I'm clearly having problems with referencing ApplicationController to monkey-patch it.

How would I manage this? I want my gem to be self-contained.

David
  • 7,028
  • 10
  • 48
  • 95
  • 1
    So you want your gem to do something without adding it to your controller code? – jkeuhlen Jul 18 '14 at 20:46
  • It will be added to the controller code. However, I want it added to the controller within the gem, not within the source code itself. – David Jul 18 '14 at 20:48
  • I don't think you can call code you don't reference but I'll leave this to someone more experienced than myself. – jkeuhlen Jul 18 '14 at 20:51
  • @jkeuhlen It isn't a matter of not referencing. It's that I'll be referencing it in my gem. The problem is I seem to have trouble referencing it in the gem. – David Jul 18 '14 at 20:53
  • But then where does your gem come into the code base? It has to be executed from somewhere? – jkeuhlen Jul 18 '14 at 20:55
  • Exactly. Apparently, from the gem I am able to target `ActionController::Base`, but when the gem loads, `ApplicationController` is not yet loaded. – David Jul 18 '14 at 21:00
  • He wants to add the code into the `ApplicationController` with the gem – Richard Peck Jul 18 '14 at 21:05
  • @RichPeck precisely. Within the gem, I want to do `ApplicationController.send :includes, MyGemModule`. Something of that sort. The issue I'm currently having is that `ApplicationController` is not yet loaded. – David Jul 18 '14 at 21:07
  • Perhaps you'll want to something like [this answer](http://stackoverflow.com/questions/11348332/how-can-i-extend-applicationcontroller-in-a-gem), and the [referenced gist](https://gist.github.com/themusicman/3057139) – Richard Peck Jul 18 '14 at 21:14
  • 1
    @RichPeck I just figured it out. Will answer this with details. – David Jul 18 '14 at 21:29

1 Answers1

0

The following code works. What I did was prematurely create ApplicationController with the appropriate inheritance. Note, many people use the rails-api gem, so I factored in them to ensure the fact that it would work.

Also, note: You must inherit from a class because otherwise ApplicationController will be a usual class that doesn't understand what after_filter is.

module CorrelationId
  module ControllerExtension

    def self.included(klass)
      klass.class_eval do
        after_filter :pass_correlation_id
      end
    end

    def pass_correlation_id
      correlation_id = request.headers['Correlation-ID'] || SecureRandom.uuid
      headers['Correlation-ID'] = correlation_id
    end

    def self.base_controller_inheritance
      if Gem::Specification.find_all_by_name('rails-api').any?
        ActionController::API
      else
        ActionController::Base
      end
    end
  end
end

class ApplicationController < CorrelationId::ControllerExtension.base_controller_inheritance
  include CorrelationId::ControllerExtension
end

I imagine there might be a better way to check if they are using ActionController::API and if so, please do share, but as of now, this seems like the most solid way to do it.

David
  • 7,028
  • 10
  • 48
  • 95