Skip to content

Commit c4fbb0f

Browse files
authored
Merge pull request rails#50150 from kmcphillips/ar-warn-legacy-adapters
Add more specific exceptions to warn when an adapter is using legacy adapter format
2 parents 9c22f35 + 79fb41d commit c4fbb0f

File tree

4 files changed

+142
-3
lines changed

4 files changed

+142
-3
lines changed

activerecord/lib/active_record/connection_adapters.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,62 @@ def resolve(adapter_name) # :nodoc:
3131
class_name, path_to_adapter = @adapters[adapter_name.to_s]
3232

3333
unless class_name
34+
# To provide better error messages for adapters expecting the pre-7.2 adapter registration API, we attempt
35+
# to load the adapter file from the old location which was required by convention, and then raise an error
36+
# describing how to upgrade the adapter to the new API.
37+
legacy_adapter_path = "active_record/connection_adapters/#{adapter_name}_adapter"
38+
legacy_adapter_connection_method_name = "#{adapter_name}_connection".to_sym
39+
40+
begin
41+
require legacy_adapter_path
42+
# If we reach here it means we found the found a file that may be the legacy adapter and should raise.
43+
if ActiveRecord::ConnectionHandling.method_defined?(legacy_adapter_connection_method_name)
44+
# If we find the connection method then we care certain it is a legacy adapter.
45+
deprecation_message = <<~MSG.squish
46+
Database configuration specifies '#{adapter_name}' adapter but that adapter has not been registered.
47+
Rails 7.2 has changed the way Active Record database adapters are loaded. The adapter needs to be
48+
updated to register itself rather than being loaded by convention.
49+
Ensure that the adapter in the Gemfile is at the latest version. If it is, then the adapter may need to
50+
be modified.
51+
See:
52+
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters.html#method-c-register
53+
MSG
54+
55+
exception_message = <<~MSG.squish
56+
Database configuration specifies '#{adapter_name}' adapter but that adapter has not been registered.
57+
Ensure that the adapter in the Gemfile is at the latest version. If it is, then the adapter may need to
58+
be modified.
59+
MSG
60+
else
61+
# If we do not find the connection method we are much less certain it is a legacy adapter. Even though the
62+
# file exists in the location defined by convenntion, it does not necessarily mean that file is supposed
63+
# to define the adapter the legacy way. So raise an error that explains both possibilities.
64+
deprecation_message = <<~MSG.squish
65+
Database configuration specifies nonexistent '#{adapter_name}' adapter.
66+
Available adapters are: #{@adapters.keys.sort.join(", ")}.
67+
Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
68+
adapter gem to your Gemfile if it's not in the list of available adapters.
69+
Rails 7.2 has changed the way Active Record database adapters are loaded. Ensure that the adapter in
70+
the Gemfile is at the latest version. If it is up to date, the adapter may need to be modified.
71+
See:
72+
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters.html#method-c-register
73+
MSG
74+
75+
exception_message = <<~MSG.squish
76+
Database configuration specifies nonexistent '#{adapter_name}' adapter.
77+
Available adapters are: #{@adapters.keys.sort.join(", ")}.
78+
Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
79+
adapter gem to your Gemfile and that it is at its latest version. If it is up to date, the adapter may
80+
need to be modified.
81+
MSG
82+
end
83+
84+
ActiveRecord.deprecator.warn(deprecation_message)
85+
raise AdapterNotFound, exception_message
86+
rescue LoadError => error
87+
# The adapter was not found in the legacy location so fall through to the error handling for a missing adapter.
88+
end
89+
3490
raise AdapterNotFound, <<~MSG.squish
3591
Database configuration specifies nonexistent '#{adapter_name}' adapter.
3692
Available adapters are: #{@adapters.keys.sort.join(", ")}.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
module ActiveRecord
4+
module ConnectionHandling
5+
def fake_legacy_connection(config)
6+
ConnectionAdapters::FakeLegacyAdapter.new nil, logger
7+
end
8+
end
9+
10+
module ConnectionAdapters
11+
class FakeLegacyAdapter < AbstractAdapter
12+
def active?
13+
true
14+
end
15+
end
16+
end
17+
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# frozen_string_literal: true
2+
3+
module ActiveRecord
4+
module ConnectionAdapters
5+
class FakeMisleadingLegacyAdapter < AbstractAdapter
6+
end
7+
end
8+
end

activerecord/test/cases/connection_adapters/registration_test.rb

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,92 @@ def teardown
1616
end
1717

1818
test "#register registers a new database adapter and #resolve can find it and raises if it cannot" do
19-
assert_raises(ActiveRecord::AdapterNotFound) do
19+
exception = assert_raises(ActiveRecord::AdapterNotFound) do
2020
ActiveRecord::ConnectionAdapters.resolve("fake")
2121
end
2222

23+
assert_match(
24+
/Database configuration specifies nonexistent 'fake' adapter. Available adapters are:/,
25+
exception.message
26+
)
27+
2328
ActiveRecord::ConnectionAdapters.register("fake", "FakeActiveRecordAdapter", @fake_adapter_path)
2429

2530
assert_equal "FakeActiveRecordAdapter", ActiveRecord::ConnectionAdapters.resolve("fake").name
2631
end
2732

2833
test "#register allows for symbol key" do
29-
assert_raises(ActiveRecord::AdapterNotFound) do
34+
exception = assert_raises(ActiveRecord::AdapterNotFound) do
3035
ActiveRecord::ConnectionAdapters.resolve("fake")
3136
end
3237

38+
assert_match(
39+
/Database configuration specifies nonexistent 'fake' adapter. Available adapters are:/,
40+
exception.message
41+
)
42+
3343
ActiveRecord::ConnectionAdapters.register(:fake, "FakeActiveRecordAdapter", @fake_adapter_path)
3444

3545
assert_equal "FakeActiveRecordAdapter", ActiveRecord::ConnectionAdapters.resolve("fake").name
3646
end
3747

3848
test "#resolve allows for symbol key" do
39-
assert_raises(ActiveRecord::AdapterNotFound) do
49+
exception = assert_raises(ActiveRecord::AdapterNotFound) do
4050
ActiveRecord::ConnectionAdapters.resolve("fake")
4151
end
4252

53+
assert_match(
54+
/Database configuration specifies nonexistent 'fake' adapter. Available adapters are:/,
55+
exception.message
56+
)
57+
4358
ActiveRecord::ConnectionAdapters.register("fake", "FakeActiveRecordAdapter", @fake_adapter_path)
4459

4560
assert_equal "FakeActiveRecordAdapter", ActiveRecord::ConnectionAdapters.resolve(:fake).name
4661
end
4762
end
63+
64+
class RegistrationIsolatedTest < ActiveRecord::TestCase
65+
include ActiveSupport::Testing::Isolation
66+
67+
def setup
68+
@original_adapters = ActiveRecord::ConnectionAdapters.instance_variable_get(:@adapters).dup
69+
end
70+
71+
test "#resolve raises if the adapter is using the pre 7.2 adapter registration API" do
72+
exception = assert_raises(ActiveRecord::AdapterNotFound) do
73+
assert_deprecated(ActiveRecord.deprecator) do
74+
ActiveRecord::ConnectionAdapters.resolve("fake_legacy")
75+
end
76+
end
77+
78+
assert_match(
79+
/Database configuration specifies 'fake_legacy' adapter but that adapter has not been registered. Ensure that the adapter in the Gemfile is at the latest version. If it is, then the adapter may need to be modified./,
80+
exception.message
81+
)
82+
ensure
83+
ActiveRecord::ConnectionAdapters.instance_variable_get(:@adapters).delete("fake_legacy")
84+
end
85+
86+
test "#resolve raises if the adapter maybe is using the pre 7.2 adapter registration API but we are not sure" do
87+
exception = assert_raises(ActiveRecord::AdapterNotFound) do
88+
assert_deprecated(ActiveRecord.deprecator) do
89+
ActiveRecord::ConnectionAdapters.resolve("fake_misleading_legacy")
90+
end
91+
end
92+
93+
assert_match(
94+
/Database configuration specifies nonexistent 'fake_misleading_legacy' adapter. Available adapters are:/,
95+
exception.message
96+
)
97+
98+
assert_match(
99+
/Ensure that the adapter is spelled correctly in config\/database.yml and that you've added the necessary adapter gem to your Gemfile and that it is at its latest version. If it is up to date, the adapter may need to be modified./,
100+
exception.message
101+
)
102+
ensure
103+
ActiveRecord::ConnectionAdapters.instance_variable_get(:@adapters).delete("fake_misleading_legacy")
104+
end
105+
end
48106
end
49107
end

0 commit comments

Comments
 (0)