aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEileen Uchitelle <eileencodes@gmail.com>2019-02-01 11:33:48 -0500
committerEileen Uchitelle <eileencodes@gmail.com>2019-02-01 14:11:35 -0500
commit8d32346cdec04dd85ab682eeb9f4edfcd0c9ccef (patch)
tree35ad1286d0328876eb6e49c61d8ed2044e38f023
parent79bc9e81c3d47be6336223be39cb3bcaeddc0a39 (diff)
downloadrails-8d32346cdec04dd85ab682eeb9f4edfcd0c9ccef.tar.gz
rails-8d32346cdec04dd85ab682eeb9f4edfcd0c9ccef.tar.bz2
rails-8d32346cdec04dd85ab682eeb9f4edfcd0c9ccef.zip
Add ability to change the names of the default handlers
When I wrote the `connected_to` and `connects_to` API's I wrote them with the idea in mind that it didn't really matter what the handlers/roles were called as long as those connecting to the roles knew which one wrote and which one read. With the introduction of the middleware Rails begins to assume it's `writing` and `reading` and there's no room for other roles. At GitHub we've been using this method for a long time so we have a ton of legacy code that uses different handler names `default` and `readonly`. We could rename all our code but I think this is better for a few reasons: - Legacy apps that have been using multiple databases for a long time can have an eaiser time switching. - If we later find this to cause more issues than it's worth we can easily deprecate. - We won't force old apps to rewrite the resolver middleware just to use a different handler. Adding the writing_role/reading_role required that I move the code that creates the first handler for writing to the railtie. If I didn't move this the core class would assign the handler before I was able to assign a new one in my configuration and I'd end up with 3 handlers instead of 2.
-rw-r--r--activerecord/lib/active_record/core.rb5
-rw-r--r--activerecord/lib/active_record/middleware/database_selector/resolver.rb6
-rw-r--r--activerecord/lib/active_record/railtie.rb1
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handler_test.rb5
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb42
-rw-r--r--activerecord/test/support/connection.rb1
6 files changed, 56 insertions, 4 deletions
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 519acd7605..84604452f7 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -125,6 +125,10 @@ module ActiveRecord
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 @@ module ActiveRecord
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 acdb9b3238..fc71835cea 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 @@ module ActiveRecord
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 @@ module ActiveRecord
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 @@ module ActiveRecord
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 a981fa97d9..f0b5ab2f08 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -197,6 +197,7 @@ end_error
# 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 51d0cc3d12..6282759a10 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 @@ module ActiveRecord
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 8988755d24..36591097b6 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 @@ module ActiveRecord
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 @@ module ActiveRecord
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 2a4fa53460..367309dd85 100644
--- a/activerecord/test/support/connection.rb
+++ b/activerecord/test/support/connection.rb
@@ -21,6 +21,7 @@ module ARTest
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