How to keep my gem self-contained without having to edit any core source Rails?

北城余情 提交于 2019-12-12 02:59:39

问题


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.


回答1:


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.



来源:https://stackoverflow.com/questions/24831530/how-to-keep-my-gem-self-contained-without-having-to-edit-any-core-source-rails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!