Skip to content

Commit ff66477

Browse files
committed
Allow removing LocalCache middleware in application.rb
All other middlewares can be removed from the stack in `config/application.rb`. `ActiveSupport::Cache::Strategy::LocalCache::Middleware` cannot, because it is added to the stack as an instance rather than a class, here: https://github.com/rails/rails/blob/main/railties/lib/rails/application/bootstrap.rb#L62. As a result, [this check](https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/middleware/stack.rb#L133) fails unless you also pass the same instance. The instance is not available in `config/appliaction.rb` because `Rails.cache` has not been initialized yet (it's initialized when the middleware is set). This means that if you want to remove the local cache middleware you have to make an initiailzer just for that. Unlike all other middlewares which can be dealt with as classes in `config/application.rb`. The fix is to check the middleware's `name`, not `klass`, for delete operations. The name is [provided explicitly](https://github.com/rails/rails/blob/main/activesupport/lib/active_support/cache/strategy/local_cache.rb#L162) presumably for this reason.
1 parent 3248812 commit ff66477

File tree

2 files changed

+96
-5
lines changed

2 files changed

+96
-5
lines changed

actionpack/lib/action_dispatch/middleware/stack.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def swap(target, *args, &block)
130130
ruby2_keywords(:swap)
131131

132132
def delete(target)
133-
middlewares.delete_if { |m| m.klass == target }
133+
middlewares.delete_if { |m| m.name == target.name }
134134
end
135135

136136
def move(target, source)
@@ -180,10 +180,10 @@ def build_middleware(klass, args, block)
180180
Middleware.new(klass, args, block)
181181
end
182182

183-
def index_of(index)
184-
raise "ActionDispatch::MiddlewareStack::FakeRuntime can not be referenced in middleware operations" if index == FakeRuntime
183+
def index_of(klass)
184+
raise "ActionDispatch::MiddlewareStack::FakeRuntime can not be referenced in middleware operations" if klass == FakeRuntime
185185

186-
if index == Rack::Runtime && @rack_runtime_deprecated
186+
if klass == Rack::Runtime && @rack_runtime_deprecated
187187
ActiveSupport::Deprecation.warn(<<-MSG.squish)
188188
Rack::Runtime is removed from the default middleware stack in Rails
189189
and referencing it in middleware operations without adding it back
@@ -192,7 +192,7 @@ def index_of(index)
192192
end
193193

194194
middlewares.index do |m|
195-
m.klass == index || (@rack_runtime_deprecated && m.klass == FakeRuntime && index == Rack::Runtime)
195+
m.name == klass.name || (@rack_runtime_deprecated && m.klass == FakeRuntime && klass == Rack::Runtime)
196196
end
197197
end
198198
end

railties/test/application/configuration_test.rb

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,6 +3226,97 @@ class MyLogger < ::Logger
32263226
assert_no_match(/You are running SQLite in production, this is generally not recommended/, Rails.logger.recording)
32273227
end
32283228

3229+
test "app starts with LocalCache middleware" do
3230+
app "development"
3231+
3232+
assert(Rails.application.config.middleware.map(&:name).include?("ActiveSupport::Cache::Strategy::LocalCache"))
3233+
3234+
local_cache_index = Rails.application.config.middleware.map(&:name).index("ActiveSupport::Cache::Strategy::LocalCache")
3235+
logger_index = Rails.application.config.middleware.map(&:name).index("Rails::Rack::Logger")
3236+
assert local_cache_index < logger_index
3237+
end
3238+
3239+
test "LocalCache middleware can be moved via app config" do
3240+
# you can't move Rails.cache.middleware as it doesn't exist yet
3241+
add_to_config "config.middleware.move_after(Rails::Rack::Logger, ActiveSupport::Cache::Strategy::LocalCache)"
3242+
3243+
app "development"
3244+
3245+
local_cache_index = Rails.application.config.middleware.map(&:name).index("ActiveSupport::Cache::Strategy::LocalCache")
3246+
logger_index = Rails.application.config.middleware.map(&:name).index("Rails::Rack::Logger")
3247+
assert local_cache_index > logger_index
3248+
end
3249+
3250+
test "LocalCache middleware can be moved via initializer" do
3251+
app_file "config/initializers/move_local_cache_middleware.rb", <<~RUBY
3252+
Rails.application.config.middleware.move_after(Rails::Rack::Logger, Rails.cache.middleware)
3253+
RUBY
3254+
3255+
app "development"
3256+
3257+
local_cache_index = Rails.application.config.middleware.map(&:name).index("ActiveSupport::Cache::Strategy::LocalCache")
3258+
logger_index = Rails.application.config.middleware.map(&:name).index("Rails::Rack::Logger")
3259+
assert local_cache_index > logger_index
3260+
end
3261+
3262+
test "LocalCache middleware can be removed via app config" do
3263+
# you can't delete Rails.cache.middleware as it doesn't exist yet
3264+
add_to_config "config.middleware.delete(ActiveSupport::Cache::Strategy::LocalCache)"
3265+
3266+
app "development"
3267+
3268+
assert_not(Rails.application.config.middleware.map(&:name).include?("ActiveSupport::Cache::Strategy::LocalCache"))
3269+
end
3270+
3271+
test "LocalCache middleware can be removed via initializer" do
3272+
app_file "config/initializers/remove_local_cache_middleware.rb", <<~RUBY
3273+
Rails.application.config.middleware.delete(Rails.cache.middleware)
3274+
RUBY
3275+
3276+
app "development"
3277+
3278+
assert_not(Rails.application.config.middleware.map(&:name).include?("ActiveSupport::Cache::Strategy::LocalCache"))
3279+
end
3280+
3281+
test "custom middleware with overridden names can be added, moved, or deleted" do
3282+
app_file "config/initializers/add_custom_middleware.rb", <<~RUBY
3283+
class CustomMiddlewareOne
3284+
def self.name
3285+
"1st custom middleware"
3286+
end
3287+
def initialize(app, *args); end
3288+
def new(app); self; end
3289+
end
3290+
3291+
class CustomMiddlewareTwo
3292+
def initialize(app, *args); end
3293+
def new(app); self; end
3294+
end
3295+
3296+
class CustomMiddlewareThree
3297+
def self.name
3298+
"3rd custom middleware"
3299+
end
3300+
def initialize(app, *args); end
3301+
def new(app); self; end
3302+
end
3303+
3304+
Rails.application.config.middleware.use(CustomMiddlewareOne)
3305+
Rails.application.config.middleware.use(CustomMiddlewareTwo)
3306+
Rails.application.config.middleware.use(CustomMiddlewareThree)
3307+
Rails.application.config.middleware.move_after(CustomMiddlewareTwo, CustomMiddlewareOne)
3308+
Rails.application.config.middleware.delete(CustomMiddlewareThree)
3309+
RUBY
3310+
3311+
app "development"
3312+
3313+
custom_middleware_one = Rails.application.config.middleware.map(&:name).index("1st custom middleware")
3314+
custom_middleware_two = Rails.application.config.middleware.map(&:name).index("CustomMiddlewareTwo")
3315+
assert custom_middleware_one > custom_middleware_two
3316+
3317+
assert_nil Rails.application.config.middleware.map(&:name).index("3rd custom middleware")
3318+
end
3319+
32293320
private
32303321
def set_custom_config(contents, config_source = "custom".inspect)
32313322
app_file "config/custom.yml", contents

0 commit comments

Comments
 (0)