diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 519acd7605ae9c90900e7b61baf9d53c42f6ef7d..84604452f7b859942424e354284f2e360a2efb5a 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -125,6 +125,10 @@ def self.configurations mattr_accessor :connection_handlers, instance_accessor: false, default: {} + mattr_accessor :writing_role, instance_accessor: false, default: :writing + + mattr_accessor :reading_role, instance_accessor: false, default: :reading + class_attribute :default_connection_handler, instance_writer: false self.filter_attributes = [] @@ -138,7 +142,6 @@ def self.connection_handler=(handler) end self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new - self.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler } end module ClassMethods diff --git a/activerecord/lib/active_record/middleware/database_selector/resolver.rb b/activerecord/lib/active_record/middleware/database_selector/resolver.rb index acdb9b32388e703e7bbbfe929e7fa3826da31bb0..fc71835cea04cdbe4ad1a4738ebddcec8da8d517 100644 --- a/activerecord/lib/active_record/middleware/database_selector/resolver.rb +++ b/activerecord/lib/active_record/middleware/database_selector/resolver.rb @@ -45,7 +45,7 @@ def write(&blk) def read_from_primary(&blk) ActiveRecord::Base.connection.while_preventing_writes do - ActiveRecord::Base.connected_to(role: :writing) do + ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do instrumenter.instrument("database_selector.active_record.read_from_primary") do yield end @@ -54,7 +54,7 @@ def read_from_primary(&blk) end def read_from_replica(&blk) - ActiveRecord::Base.connected_to(role: :reading) do + ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role) do instrumenter.instrument("database_selector.active_record.read_from_replica") do yield end @@ -62,7 +62,7 @@ def read_from_replica(&blk) end def write_to_primary(&blk) - ActiveRecord::Base.connected_to(role: :writing) do + ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do instrumenter.instrument("database_selector.active_record.wrote_to_primary") do yield ensure diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index a981fa97d90d53141116b7f57e147204f3118f95..f0b5ab2f087c4e467a2ffa39d5904c278ec8b22a 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -197,6 +197,7 @@ class Railtie < Rails::Railtie # :nodoc: # and then establishes the connection. initializer "active_record.initialize_database" do ActiveSupport.on_load(:active_record) do + self.connection_handlers = { writing_role => ActiveRecord::Base.default_connection_handler } self.configurations = Rails.application.config.database_configuration establish_connection end diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb index 51d0cc3d12513472f4010dbf5f26f6449d65fa95..6282759a108efc0a7f2131d230be648b45873040 100644 --- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb @@ -382,6 +382,11 @@ def test_remove_connection_should_not_remove_parent assert_not_nil ActiveRecord::Base.connection assert_same klass2.connection, ActiveRecord::Base.connection end + + def test_default_handlers_are_writing_and_reading + assert_equal :writing, ActiveRecord::Base.writing_role + assert_equal :reading, ActiveRecord::Base.reading_role + end end end end diff --git a/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb b/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb index 8988755d24cf786d42e3c60b1c3ea8e36589328a..36591097b6b62c894ecbdfe419b1c7c493a3b862 100644 --- a/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb @@ -126,6 +126,30 @@ def test_switching_connections_via_handler ENV["RAILS_ENV"] = previous_env end + def test_establish_connection_using_3_levels_config_with_non_default_handlers + previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env" + + config = { + "default_env" => { + "readonly" => { "adapter" => "sqlite3", "database" => "db/readonly.sqlite3" }, + "primary" => { "adapter" => "sqlite3", "database" => "db/primary.sqlite3" } + } + } + @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config + + ActiveRecord::Base.connects_to(database: { default: :primary, readonly: :readonly }) + + assert_not_nil pool = ActiveRecord::Base.connection_handlers[:default].retrieve_connection_pool("primary") + assert_equal "db/primary.sqlite3", pool.spec.config[:database] + + assert_not_nil pool = ActiveRecord::Base.connection_handlers[:readonly].retrieve_connection_pool("primary") + assert_equal "db/readonly.sqlite3", pool.spec.config[:database] + ensure + ActiveRecord::Base.configurations = @prev_configs + ActiveRecord::Base.establish_connection(:arunit) + ENV["RAILS_ENV"] = previous_env + end + def test_switching_connections_with_database_url previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env" previous_url, ENV["DATABASE_URL"] = ENV["DATABASE_URL"], "postgres://localhost/foo" @@ -344,6 +368,24 @@ def test_calling_connected_to_on_a_non_existent_handler_raises assert_equal "No connection pool with 'primary' found for the 'reading' role.", error.message end + + def test_default_handlers_are_writing_and_reading + assert_equal :writing, ActiveRecord::Base.writing_role + assert_equal :reading, ActiveRecord::Base.reading_role + end + + def test_an_application_can_change_the_default_handlers + old_writing = ActiveRecord::Base.writing_role + old_reading = ActiveRecord::Base.reading_role + ActiveRecord::Base.writing_role = :default + ActiveRecord::Base.reading_role = :readonly + + assert_equal :default, ActiveRecord::Base.writing_role + assert_equal :readonly, ActiveRecord::Base.reading_role + ensure + ActiveRecord::Base.writing_role = old_writing + ActiveRecord::Base.reading_role = old_reading + end end end end diff --git a/activerecord/test/support/connection.rb b/activerecord/test/support/connection.rb index 2a4fa53460b7f48177fcad546e23132baaa21227..367309dd85a89d538373e79c06850b08cb3972c8 100644 --- a/activerecord/test/support/connection.rb +++ b/activerecord/test/support/connection.rb @@ -21,6 +21,7 @@ def self.connection_config def self.connect puts "Using #{connection_name}" ActiveRecord::Base.logger = ActiveSupport::Logger.new("debug.log", 0, 100 * 1024 * 1024) + ActiveRecord::Base.connection_handlers = { ActiveRecord::Base.writing_role => ActiveRecord::Base.default_connection_handler } ActiveRecord::Base.configurations = connection_config ActiveRecord::Base.establish_connection :arunit ARUnit2Model.establish_connection :arunit2