Skip to content
This repository has been archived by the owner on Dec 8, 2020. It is now read-only.

Commit

Permalink
Make sure Timber is the absolute last middleware inserted (#79)
Browse files Browse the repository at this point in the history
* Make Timber is the absolute last middleware inserted

* Remove require

* Fix specs

* Cleanup

* Cleanup

* Rescue NameError

* Merge initializers now
  • Loading branch information
binarylogic authored Apr 21, 2017
1 parent d0473e7 commit 0023195
Showing 1 changed file with 47 additions and 18 deletions.
65 changes: 47 additions & 18 deletions lib/timber/frameworks/rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,64 @@ module Frameworks
# Module for Rails specific code, such as the Railtie and any methods that assist
# with Rails setup.
module Rails
# Because of the crazy way Rails sorts it's initializers, it is
# impossible for Timber to be inserted after Devise's omnitauth
# middlewares.
# See: https://github.com/plataformatec/devise/blob/master/lib/devise/rails.rb#L22
# As such, we take a brute force approach here, ensuring we are inserted last
# no matter what. This ensures that we come after authentication so that we can
# properly set the user context.
#
# @private
module MiddlewareStackProxyFix
def self.included(klass)
klass.class_eval do
attr_accessor :timber_operations

alias old_merge_into merge_into

# This method does not exist for older versions of rails
begin
alias old_plus +
rescue NameError
end

def +(*args)
result = old_plus(*args)
result.timber_operations = timber_operations
result
end

def merge_into(*args)
if timber_operations
@operations -= timber_operations
@operations += timber_operations
end
old_merge_into(*args)
end
end
end
end

::Rails::Configuration::MiddlewareStackProxy.send(:include, MiddlewareStackProxyFix)

# Installs Timber into your Rails app automatically.
class Railtie < ::Rails::Railtie
config.timber = Config.instance

# Initialize Timber immediately after the logger in case anything uses the logger
# during the initialization process.
initializer(:timber, group: :all, after: :initialize_logger) do
initializer(:timber, after: :initialize_logger) do
logger = Rails.ensure_timber_logger(::Rails.logger)
Rails.set_logger(logger)

Integrations.integrate!
end

# Ensures that we insert the middlewares last. We need to insert these last
# because initializers, such as Omniauth, insert middleware. If we are not
# after these initializers we will not capture user context, for example.
initializer(:timber_middlewares, after: :engines_blank_point) do
Rails.configure_middlewares(config.app_middleware)
timber_operations = Integrations::Rack.middlewares.collect do |middleware_class|
[:use, [middleware_class], nil]
end

config.app_middleware.timber_operations = timber_operations
end
end

Expand Down Expand Up @@ -60,17 +100,6 @@ def self.set_logger(logger)
::ActiveRecord::Base.logger = logger if defined?(::ActiveRecord::Base) && ::ActiveRecord::Base.respond_to?(:logger=)
::Rails.logger = logger
end

def self.configure_middlewares(middleware)
var_name = :"@_timber_middlewares_inserted"
return true if middleware.instance_variable_defined?(var_name) && middleware.instance_variable_get(var_name) == true

# Rails uses a proxy :/, so we need to do this instance variable hack
middleware.instance_variable_set(var_name, true)
Integrations::Rack.middlewares.each do |middleware_class|
middleware.use middleware_class
end
end
end
end
end

0 comments on commit 0023195

Please sign in to comment.