Skip to content

Commit 0af96d2

Browse files
authored
Merge pull request rails#50093 from kmcphillips/ar-adapter-alias
Delay validation of registered Active Record adapters and allow aliasing of adapters
2 parents 6305bd7 + 77df3d5 commit 0af96d2

File tree

8 files changed

+105
-10
lines changed

8 files changed

+105
-10
lines changed

activerecord/lib/active_record/connection_adapters.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ class << self
1818
# ActiveRecord::ConnectionAdapters.register("mysql", "ActiveRecord::ConnectionAdapters::TrilogyAdapter", "active_record/connection_adapters/trilogy_adapter")
1919
#
2020
def register(name, class_name, path = class_name.underscore)
21-
@adapters[name] = [class_name, path]
21+
@adapters[name.to_s] = [class_name, path]
2222
end
2323

2424
def resolve(adapter_name) # :nodoc:
2525
# Require the adapter itself and give useful feedback about
2626
# 1. Missing adapter gems.
2727
# 2. Incorrectly registered adapters.
2828
# 3. Adapter gems' missing dependencies.
29-
class_name, path_to_adapter = @adapters[adapter_name]
29+
class_name, path_to_adapter = @adapters[adapter_name.to_s]
3030

3131
unless class_name
3232
raise AdapterNotFound, <<~MSG.squish

activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def disconnect_pool_from_pool_manager(pool_manager, role, shard)
322322
#
323323
def resolve_pool_config(config, connection_name, role, shard)
324324
db_config = Base.configurations.resolve(config)
325-
325+
db_config.validate!
326326
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless db_config.adapter
327327
ConnectionAdapters::PoolConfig.new(connection_name, db_config, role, shard)
328328
end

activerecord/lib/active_record/database_configurations/database_config.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ class DatabaseConfigurations
88
class DatabaseConfig # :nodoc:
99
attr_reader :env_name, :name
1010

11-
def self.new(...)
12-
instance = super
13-
instance.adapter_class if instance.adapter # Ensure resolution happens early
14-
instance
15-
end
16-
1711
def initialize(env_name, name)
1812
@env_name = env_name
1913
@name = name
@@ -28,6 +22,12 @@ def new_connection
2822
adapter_class.new(configuration_hash)
2923
end
3024

25+
def validate!
26+
adapter_class if adapter
27+
28+
true
29+
end
30+
3131
def host
3232
raise NotImplementedError
3333
end

activerecord/test/cases/connection_adapters/connection_handler_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ def test_establish_connection_using_3_levels_config
6363
ENV["RAILS_ENV"] = previous_env
6464
end
6565

66+
def test_validates_db_configuration_and_raises_on_invalid_adapter
67+
config = {
68+
"development" => { "adapter" => "ridiculous" },
69+
}
70+
71+
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
72+
73+
assert_raises(ActiveRecord::AdapterNotFound) do
74+
ActiveRecord::Base.establish_connection(:development)
75+
end
76+
ensure
77+
ActiveRecord::Base.configurations = @prev_configs
78+
end
79+
6680
unless in_memory_db?
6781
def test_not_setting_writing_role_while_using_another_named_role_raises
6882
connection_handler = ActiveRecord::Base.connection_handler
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# frozen_string_literal: true
2+
3+
require "cases/helper"
4+
5+
module ActiveRecord
6+
module ConnectionAdapters
7+
class RegistrationTest < ActiveRecord::TestCase
8+
def setup
9+
@original_adapters = ActiveRecord::ConnectionAdapters.instance_variable_get(:@adapters).dup
10+
ActiveRecord::ConnectionAdapters.instance_variable_get(:@adapters).delete("fake")
11+
@fake_adapter_path = File.expand_path("../../support/fake_adapter.rb", __dir__)
12+
end
13+
14+
def teardown
15+
ActiveRecord::ConnectionAdapters.instance_variable_set(:@adapters, @original_adapters)
16+
end
17+
18+
test "#register registers a new database adapter and #resolve can find it and raises if it cannot" do
19+
assert_raises(ActiveRecord::AdapterNotFound) do
20+
ActiveRecord::ConnectionAdapters.resolve("fake")
21+
end
22+
23+
ActiveRecord::ConnectionAdapters.register("fake", "FakeActiveRecordAdapter", @fake_adapter_path)
24+
25+
assert_equal "FakeActiveRecordAdapter", ActiveRecord::ConnectionAdapters.resolve("fake").name
26+
end
27+
28+
test "#register allows for symbol key" do
29+
assert_raises(ActiveRecord::AdapterNotFound) do
30+
ActiveRecord::ConnectionAdapters.resolve("fake")
31+
end
32+
33+
ActiveRecord::ConnectionAdapters.register(:fake, "FakeActiveRecordAdapter", @fake_adapter_path)
34+
35+
assert_equal "FakeActiveRecordAdapter", ActiveRecord::ConnectionAdapters.resolve("fake").name
36+
end
37+
38+
test "#resolve allows for symbol key" do
39+
assert_raises(ActiveRecord::AdapterNotFound) do
40+
ActiveRecord::ConnectionAdapters.resolve("fake")
41+
end
42+
43+
ActiveRecord::ConnectionAdapters.register("fake", "FakeActiveRecordAdapter", @fake_adapter_path)
44+
45+
assert_equal "FakeActiveRecordAdapter", ActiveRecord::ConnectionAdapters.resolve(:fake).name
46+
end
47+
end
48+
end
49+
end

activerecord/test/cases/database_configurations/hash_config_test.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,15 @@ def test_schema_cache_path_configuration_hash
145145
config = HashConfig.new("default_env", "primary", { schema_cache_path: "db/config_schema_cache.yml", adapter: "abstract" })
146146
assert_equal "db/config_schema_cache.yml", config.schema_cache_path
147147
end
148+
149+
def test_validate_checks_the_adapter_exists
150+
config = HashConfig.new("default_env", "primary", adapter: "abstract")
151+
assert config.validate!
152+
config = HashConfig.new("default_env", "primary", adapter: "potato")
153+
assert_raises(ActiveRecord::AdapterNotFound) do
154+
config.validate!
155+
end
156+
end
148157
end
149158
end
150159
end

railties/lib/rails/commands/dbconsole/dbconsole_command.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ def db_config
3737
"#{missing_db} configured for '#{environment}'. Available configuration: #{configurations.inspect}"
3838
end
3939

40+
@db_config.validate!
41+
4042
@db_config
4143
end
4244

@@ -51,7 +53,7 @@ def environment
5153
private
5254
def adapter_class
5355
ActiveRecord::ConnectionAdapters.resolve(db_config.adapter)
54-
rescue LoadError, ActiveRecord::AdapterNotFound
56+
rescue LoadError
5557
ActiveRecord::ConnectionAdapters::AbstractAdapter
5658
end
5759

railties/test/application/configuration_test.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4770,6 +4770,27 @@ class Foo < ApplicationRecord
47704770
assert_equal [:foo], Foo.attributes_for_inspect
47714771
end
47724772

4773+
test "new Active Record connection adapters can be registered as aliases in application initializers" do
4774+
app_file "config/database.yml", <<-YAML
4775+
development:
4776+
adapter: potato
4777+
database: 'example_db'
4778+
YAML
4779+
4780+
app_file "config/initializers/active_record_connection_adapters.rb", <<-RUBY
4781+
ActiveRecord::ConnectionAdapters.register(
4782+
"potato",
4783+
"ActiveRecord::ConnectionAdapters::SQLite3Adapter",
4784+
"active_record/connection_adapters/sqlite3_adapter"
4785+
)
4786+
RUBY
4787+
4788+
app "development"
4789+
4790+
assert_equal "potato", ActiveRecord::Base.connection.pool.db_config.adapter
4791+
assert_equal "SQLite", ActiveRecord::Base.connection.adapter_name
4792+
end
4793+
47734794
private
47744795
def set_custom_config(contents, config_source = "custom".inspect)
47754796
app_file "config/custom.yml", contents

0 commit comments

Comments
 (0)