Move db and shard selector initalizer to Railties

In #45162 it was discovered that the multi_db generator that was created
for 7.0 doesn't work correctly because that file is loaded _after_ the
initializer in active record is run. I tried moving everything to an
after_initialize but the middleware stack is frozen at that point. I
also attempted to fix this in #45353 but it just didn't feel right to
have to deprecate this behavior that _should_ work.

I then realized that most of the middleware in Rails is installed in the
middleware stack file in railties. If I move the middleware installation
to this file, everything works as necessary.

The only caveat is we need to check if `config` responds to
`active_record` but I think that should be fine - we already do that in
the framework defaults configuration.

Fixes #45162
This commit is contained in:
eileencodes 2022-06-15 11:25:16 -04:00
parent 7f93661551
commit d179383284
No known key found for this signature in database
GPG Key ID: BA5C575120BBE8DF
3 changed files with 50 additions and 16 deletions

View File

@ -94,22 +94,6 @@ module ActiveRecord
end
end
initializer "active_record.database_selector" do
if options = config.active_record.database_selector
resolver = config.active_record.database_resolver
operations = config.active_record.database_resolver_context
config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
end
end
initializer "active_record.shard_selector" do
if resolver = config.active_record.shard_resolver
options = config.active_record.shard_selector || {}
config.app_middleware.use ActiveRecord::Middleware::ShardSelector, resolver, options
end
end
initializer "Check for cache versioning support" do
config.after_initialize do |app|
ActiveSupport.on_load(:active_record) do

View File

@ -81,6 +81,21 @@ module Rails
middleware.use ::Rack::ETag, "no-cache"
middleware.use ::Rack::TempfileReaper unless config.api_only
if config.respond_to?(:active_record)
if selector_options = config.active_record.database_selector
resolver = config.active_record.database_resolver
context = config.active_record.database_resolver_context
middleware.use ::ActiveRecord::Middleware::DatabaseSelector, resolver, context, selector_options
end
if shard_resolver = config.active_record.shard_resolver
options = config.active_record.shard_selector || {}
middleware.use ::ActiveRecord::Middleware::ShardSelector, shard_resolver, options
end
end
end
end

View File

@ -345,6 +345,28 @@ module ApplicationTests
assert_equal "/foo/?something", env["ORIGINAL_FULLPATH"]
end
test "database selector middleware is installed from application.rb" do
add_to_config "config.active_record.database_selector = { delay: 10 }"
boot!
assert_includes middleware, "ActiveRecord::Middleware::DatabaseSelector"
end
test "database selector middleware is installed from config/initializers" do
app_file "config/initializers/multi_db.rb", <<-RUBY
Rails.application.configure do
config.active_record.database_selector = { delay: 15.seconds }
config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end
RUBY
boot!
assert_includes middleware, "ActiveRecord::Middleware::DatabaseSelector"
end
test "shard selector middleware is installed by config option" do
add_to_config "config.active_record.shard_resolver = ->(*) { }"
@ -353,6 +375,19 @@ module ApplicationTests
assert_includes middleware, "ActiveRecord::Middleware::ShardSelector"
end
test "shard selector middleware is installed from config/initializers" do
app_file "config/initializers/multi_db.rb", <<-RUBY
Rails.application.configure do
config.active_record.shard_selector = { lock: true }
config.active_record.shard_resolver = ->(request) { Tenant.find_by!(host: request.host).shard }
end
RUBY
boot!
assert_includes middleware, "ActiveRecord::Middleware::ShardSelector"
end
private
def boot!
require "#{app_path}/config/environment"