activerecord 7.1.6 → 7.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +839 -2248
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +15 -8
- data/lib/active_record/associations/belongs_to_association.rb +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +16 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +59 -292
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +5 -25
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
- data/lib/active_record/attribute_methods.rb +51 -60
- data/lib/active_record/attributes.rb +93 -68
- data/lib/active_record/autosave_association.rb +25 -32
- data/lib/active_record/base.rb +4 -5
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +294 -72
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -75
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -6
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +46 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +6 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +19 -18
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -23
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +30 -8
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +16 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +36 -26
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +133 -78
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +68 -49
- data/lib/active_record/core.rb +112 -44
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +42 -18
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +25 -5
- data/lib/active_record/encryption/encryptor.rb +35 -19
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/enum.rb +31 -13
- data/lib/active_record/errors.rb +49 -23
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +87 -77
- data/lib/active_record/model_schema.rb +31 -68
- data/lib/active_record/nested_attributes.rb +11 -3
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +19 -0
- data/lib/active_record/querying.rb +25 -13
- data/lib/active_record/railtie.rb +39 -57
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +42 -44
- data/lib/active_record/reflection.rb +98 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +14 -8
- data/lib/active_record/relation/calculations.rb +127 -89
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +26 -12
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +238 -65
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +15 -21
- data/lib/active_record/relation.rb +508 -74
- data/lib/active_record/result.rb +31 -44
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +48 -20
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +27 -7
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +69 -41
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +8 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +86 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +73 -15
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +15 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +148 -39
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +3 -1
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +7 -3
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +31 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +16 -10
|
@@ -1,9 +1,130 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/core_ext/string/filters"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
module ConnectionAdapters
|
|
5
7
|
extend ActiveSupport::Autoload
|
|
6
8
|
|
|
9
|
+
@adapters = {}
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
# Registers a custom database adapter.
|
|
13
|
+
#
|
|
14
|
+
# Can also be used to define aliases.
|
|
15
|
+
#
|
|
16
|
+
# == Example
|
|
17
|
+
#
|
|
18
|
+
# ActiveRecord::ConnectionAdapters.register("megadb", "MegaDB::ActiveRecordAdapter", "mega_db/active_record_adapter")
|
|
19
|
+
#
|
|
20
|
+
# ActiveRecord::ConnectionAdapters.register("mysql", "ActiveRecord::ConnectionAdapters::TrilogyAdapter", "active_record/connection_adapters/trilogy_adapter")
|
|
21
|
+
#
|
|
22
|
+
def register(name, class_name, path = class_name.underscore)
|
|
23
|
+
@adapters[name.to_s] = [class_name, path]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def resolve(adapter_name) # :nodoc:
|
|
27
|
+
# Require the adapter itself and give useful feedback about
|
|
28
|
+
# 1. Missing adapter gems.
|
|
29
|
+
# 2. Incorrectly registered adapters.
|
|
30
|
+
# 3. Adapter gems' missing dependencies.
|
|
31
|
+
class_name, path_to_adapter = @adapters[adapter_name.to_s]
|
|
32
|
+
|
|
33
|
+
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
|
+
|
|
90
|
+
raise AdapterNotFound, <<~MSG.squish
|
|
91
|
+
Database configuration specifies nonexistent '#{adapter_name}' adapter.
|
|
92
|
+
Available adapters are: #{@adapters.keys.sort.join(", ")}.
|
|
93
|
+
Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
|
|
94
|
+
adapter gem to your Gemfile if it's not in the list of available adapters.
|
|
95
|
+
MSG
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
unless Object.const_defined?(class_name)
|
|
99
|
+
begin
|
|
100
|
+
require path_to_adapter
|
|
101
|
+
rescue LoadError => error
|
|
102
|
+
# We couldn't require the adapter itself.
|
|
103
|
+
if error.path == path_to_adapter
|
|
104
|
+
# We can assume here that a non-builtin adapter was specified and the path
|
|
105
|
+
# registered by the adapter gem is incorrect.
|
|
106
|
+
raise LoadError, "Error loading the '#{adapter_name}' Active Record adapter. Ensure that the path registered by the adapter gem is correct. #{error.message}", error.backtrace
|
|
107
|
+
else
|
|
108
|
+
# Bubbled up from the adapter require. Prefix the exception message
|
|
109
|
+
# with some guidance about how to address it and reraise.
|
|
110
|
+
raise LoadError, "Error loading the '#{adapter_name}' Active Record adapter. Missing a gem it depends on? #{error.message}", error.backtrace
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
begin
|
|
116
|
+
Object.const_get(class_name)
|
|
117
|
+
rescue NameError => error
|
|
118
|
+
raise AdapterNotFound, "Could not load the #{class_name} Active Record adapter (#{error.message})."
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
register "sqlite3", "ActiveRecord::ConnectionAdapters::SQLite3Adapter", "active_record/connection_adapters/sqlite3_adapter"
|
|
124
|
+
register "mysql2", "ActiveRecord::ConnectionAdapters::Mysql2Adapter", "active_record/connection_adapters/mysql2_adapter"
|
|
125
|
+
register "trilogy", "ActiveRecord::ConnectionAdapters::TrilogyAdapter", "active_record/connection_adapters/trilogy_adapter"
|
|
126
|
+
register "postgresql", "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter", "active_record/connection_adapters/postgresql_adapter"
|
|
127
|
+
|
|
7
128
|
eager_autoload do
|
|
8
129
|
autoload :AbstractAdapter
|
|
9
130
|
end
|
|
@@ -170,9 +170,11 @@ module ActiveRecord
|
|
|
170
170
|
prevent_writes = true if role == ActiveRecord.reading_role
|
|
171
171
|
|
|
172
172
|
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
begin
|
|
174
|
+
yield
|
|
175
|
+
ensure
|
|
176
|
+
connected_to_stack.pop
|
|
177
|
+
end
|
|
176
178
|
end
|
|
177
179
|
|
|
178
180
|
# Use a specified connection.
|
|
@@ -243,22 +245,64 @@ module ActiveRecord
|
|
|
243
245
|
# Clears the query cache for all connections associated with the current thread.
|
|
244
246
|
def clear_query_caches_for_current_thread
|
|
245
247
|
connection_handler.each_connection_pool do |pool|
|
|
246
|
-
pool.
|
|
248
|
+
pool.clear_query_cache
|
|
247
249
|
end
|
|
248
250
|
end
|
|
249
251
|
|
|
250
252
|
# Returns the connection currently associated with the class. This can
|
|
251
253
|
# also be used to "borrow" the connection to do database work unrelated
|
|
252
254
|
# to any of the specific Active Records.
|
|
255
|
+
# The connection will remain leased for the entire duration of the request
|
|
256
|
+
# or job, or until +#release_connection+ is called.
|
|
257
|
+
def lease_connection
|
|
258
|
+
connection_pool.lease_connection
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Soft deprecated. Use +#with_connection+ or +#lease_connection+ instead.
|
|
253
262
|
def connection
|
|
254
|
-
|
|
263
|
+
pool = connection_pool
|
|
264
|
+
if pool.permanent_lease?
|
|
265
|
+
case ActiveRecord.permanent_connection_checkout
|
|
266
|
+
when :deprecated
|
|
267
|
+
ActiveRecord.deprecator.warn <<~MESSAGE
|
|
268
|
+
Called deprecated `ActiveRecord::Base.connection` method.
|
|
269
|
+
|
|
270
|
+
Either use `with_connection` or `lease_connection`.
|
|
271
|
+
MESSAGE
|
|
272
|
+
when :disallowed
|
|
273
|
+
raise ActiveRecordError, <<~MESSAGE
|
|
274
|
+
Called deprecated `ActiveRecord::Base.connection` method.
|
|
275
|
+
|
|
276
|
+
Either use `with_connection` or `lease_connection`.
|
|
277
|
+
MESSAGE
|
|
278
|
+
end
|
|
279
|
+
pool.lease_connection
|
|
280
|
+
else
|
|
281
|
+
pool.active_connection
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Return the currently leased connection into the pool
|
|
286
|
+
def release_connection
|
|
287
|
+
connection_pool.release_connection
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Checkouts a connection from the pool, yield it and then check it back in.
|
|
291
|
+
# If a connection was already leased via #lease_connection or a parent call to
|
|
292
|
+
# #with_connection, that same connection is yieled.
|
|
293
|
+
# If #lease_connection is called inside the block, the connection won't be checked
|
|
294
|
+
# back in.
|
|
295
|
+
# If #connection is called inside the block, the connection won't be checked back in
|
|
296
|
+
# unless the +prevent_permanent_checkout+ argument is set to +true+.
|
|
297
|
+
def with_connection(prevent_permanent_checkout: false, &block)
|
|
298
|
+
connection_pool.with_connection(prevent_permanent_checkout: prevent_permanent_checkout, &block)
|
|
255
299
|
end
|
|
256
300
|
|
|
257
301
|
attr_writer :connection_specification_name
|
|
258
302
|
|
|
259
303
|
# Returns the connection specification name from the current class or its parent.
|
|
260
304
|
def connection_specification_name
|
|
261
|
-
if
|
|
305
|
+
if @connection_specification_name.nil?
|
|
262
306
|
return self == Base ? Base.name : superclass.connection_specification_name
|
|
263
307
|
end
|
|
264
308
|
@connection_specification_name
|
|
@@ -279,8 +323,12 @@ module ActiveRecord
|
|
|
279
323
|
connection_pool.db_config
|
|
280
324
|
end
|
|
281
325
|
|
|
326
|
+
def adapter_class # :nodoc:
|
|
327
|
+
connection_pool.db_config.adapter_class
|
|
328
|
+
end
|
|
329
|
+
|
|
282
330
|
def connection_pool
|
|
283
|
-
connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard
|
|
331
|
+
connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard, strict: true)
|
|
284
332
|
end
|
|
285
333
|
|
|
286
334
|
def retrieve_connection
|
|
@@ -292,16 +340,9 @@ module ActiveRecord
|
|
|
292
340
|
connection_handler.connected?(connection_specification_name, role: current_role, shard: current_shard)
|
|
293
341
|
end
|
|
294
342
|
|
|
295
|
-
def remove_connection
|
|
296
|
-
if
|
|
297
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
|
298
|
-
The name argument for `#remove_connection` is deprecated without replacement
|
|
299
|
-
and will be removed in Rails 7.2. `#remove_connection` should always be called
|
|
300
|
-
on the connection class directly, which makes the name argument obsolete.
|
|
301
|
-
MSG
|
|
302
|
-
end
|
|
343
|
+
def remove_connection
|
|
344
|
+
name = @connection_specification_name if defined?(@connection_specification_name)
|
|
303
345
|
|
|
304
|
-
name ||= @connection_specification_name if defined?(@connection_specification_name)
|
|
305
346
|
# if removing a connection that has a pool, we reset the
|
|
306
347
|
# connection_specification_name so it will use the parent
|
|
307
348
|
# pool.
|
|
@@ -312,39 +353,15 @@ module ActiveRecord
|
|
|
312
353
|
connection_handler.remove_connection_pool(name, role: current_role, shard: current_shard)
|
|
313
354
|
end
|
|
314
355
|
|
|
315
|
-
def
|
|
316
|
-
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
def clear_active_connections!(role = nil)
|
|
320
|
-
deprecation_for_delegation(__method__)
|
|
321
|
-
connection_handler.clear_active_connections!(role)
|
|
356
|
+
def schema_cache # :nodoc:
|
|
357
|
+
connection_pool.schema_cache
|
|
322
358
|
end
|
|
323
359
|
|
|
324
|
-
def
|
|
325
|
-
|
|
326
|
-
connection_handler.clear_reloadable_connections!(role)
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
def clear_all_connections!(role = nil)
|
|
330
|
-
deprecation_for_delegation(__method__)
|
|
331
|
-
connection_handler.clear_all_connections!(role)
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
def flush_idle_connections!(role = nil)
|
|
335
|
-
deprecation_for_delegation(__method__)
|
|
336
|
-
connection_handler.flush_idle_connections!(role)
|
|
360
|
+
def clear_cache! # :nodoc:
|
|
361
|
+
connection_pool.schema_cache.clear!
|
|
337
362
|
end
|
|
338
363
|
|
|
339
364
|
private
|
|
340
|
-
def deprecation_for_delegation(method)
|
|
341
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
|
342
|
-
Calling `ActiveRecord::Base.#{method} is deprecated. Please
|
|
343
|
-
call the method directly on the connection handler; for
|
|
344
|
-
example: `ActiveRecord::Base.connection_handler.#{method}`.
|
|
345
|
-
MSG
|
|
346
|
-
end
|
|
347
|
-
|
|
348
365
|
def resolve_config_for_connection(config_or_env)
|
|
349
366
|
raise "Anonymous class is not allowed." unless name
|
|
350
367
|
|
|
@@ -358,11 +375,13 @@ module ActiveRecord
|
|
|
358
375
|
prevent_writes = true if role == ActiveRecord.reading_role
|
|
359
376
|
|
|
360
377
|
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
378
|
+
begin
|
|
379
|
+
return_value = yield
|
|
380
|
+
return_value.load if return_value.is_a? ActiveRecord::Relation
|
|
381
|
+
return_value
|
|
382
|
+
ensure
|
|
383
|
+
self.connected_to_stack.pop
|
|
384
|
+
end
|
|
366
385
|
end
|
|
367
386
|
|
|
368
387
|
def append_to_connected_to_stack(entry)
|
data/lib/active_record/core.rb
CHANGED
|
@@ -73,7 +73,7 @@ module ActiveRecord
|
|
|
73
73
|
end
|
|
74
74
|
self.configurations = {}
|
|
75
75
|
|
|
76
|
-
# Returns fully resolved ActiveRecord::DatabaseConfigurations object
|
|
76
|
+
# Returns a fully resolved ActiveRecord::DatabaseConfigurations object.
|
|
77
77
|
def self.configurations
|
|
78
78
|
@@configurations
|
|
79
79
|
end
|
|
@@ -102,6 +102,21 @@ module ActiveRecord
|
|
|
102
102
|
|
|
103
103
|
class_attribute :shard_selector, instance_accessor: false, default: nil
|
|
104
104
|
|
|
105
|
+
##
|
|
106
|
+
# :singleton-method:
|
|
107
|
+
#
|
|
108
|
+
# Specifies the attributes that will be included in the output of the
|
|
109
|
+
# #inspect method:
|
|
110
|
+
#
|
|
111
|
+
# Post.attributes_for_inspect = [:id, :title]
|
|
112
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
|
|
113
|
+
#
|
|
114
|
+
# When set to `:all` inspect will list all the record's attributes:
|
|
115
|
+
#
|
|
116
|
+
# Post.attributes_for_inspect = :all
|
|
117
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
|
118
|
+
class_attribute :attributes_for_inspect, instance_accessor: false, default: :all
|
|
119
|
+
|
|
105
120
|
def self.application_record_class? # :nodoc:
|
|
106
121
|
if ActiveRecord.application_record_class
|
|
107
122
|
self == ActiveRecord.application_record_class
|
|
@@ -350,8 +365,8 @@ module ActiveRecord
|
|
|
350
365
|
super
|
|
351
366
|
elsif abstract_class?
|
|
352
367
|
"#{super}(abstract)"
|
|
353
|
-
elsif !connected?
|
|
354
|
-
"#{super} (call '#{super}.
|
|
368
|
+
elsif !schema_loaded? && !connected?
|
|
369
|
+
"#{super} (call '#{super}.load_schema' to load schema informations)"
|
|
355
370
|
elsif table_exists?
|
|
356
371
|
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
|
|
357
372
|
"#{super}(#{attr_list})"
|
|
@@ -373,7 +388,7 @@ module ActiveRecord
|
|
|
373
388
|
TypeCaster::Map.new(self)
|
|
374
389
|
end
|
|
375
390
|
|
|
376
|
-
def cached_find_by_statement(key, &block) # :nodoc:
|
|
391
|
+
def cached_find_by_statement(connection, key, &block) # :nodoc:
|
|
377
392
|
cache = @find_by_statement_cache[connection.prepared_statements]
|
|
378
393
|
cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
|
|
379
394
|
end
|
|
@@ -416,21 +431,23 @@ module ActiveRecord
|
|
|
416
431
|
end
|
|
417
432
|
|
|
418
433
|
def cached_find_by(keys, values)
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
434
|
+
with_connection do |connection|
|
|
435
|
+
statement = cached_find_by_statement(connection, keys) { |params|
|
|
436
|
+
wheres = keys.index_with do |key|
|
|
437
|
+
if key.is_a?(Array)
|
|
438
|
+
[key.map { params.bind }]
|
|
439
|
+
else
|
|
440
|
+
params.bind
|
|
441
|
+
end
|
|
425
442
|
end
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
}
|
|
443
|
+
where(wheres).limit(1)
|
|
444
|
+
}
|
|
429
445
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
446
|
+
begin
|
|
447
|
+
statement.execute(values.flatten, connection, allow_retry: true).first
|
|
448
|
+
rescue TypeError
|
|
449
|
+
raise ActiveRecord::StatementInvalid
|
|
450
|
+
end
|
|
434
451
|
end
|
|
435
452
|
end
|
|
436
453
|
end
|
|
@@ -450,7 +467,7 @@ module ActiveRecord
|
|
|
450
467
|
init_internals
|
|
451
468
|
initialize_internals_callback
|
|
452
469
|
|
|
453
|
-
|
|
470
|
+
super
|
|
454
471
|
|
|
455
472
|
yield self if block_given?
|
|
456
473
|
_run_initialize_callbacks
|
|
@@ -568,7 +585,7 @@ module ActiveRecord
|
|
|
568
585
|
#
|
|
569
586
|
# topic = Topic.new(title: "Budget", author_name: "Jason")
|
|
570
587
|
# topic.slice(:title, :author_name)
|
|
571
|
-
# => { "title" => "Budget", "author_name" => "Jason" }
|
|
588
|
+
# # => { "title" => "Budget", "author_name" => "Jason" }
|
|
572
589
|
#
|
|
573
590
|
#--
|
|
574
591
|
# Implemented by ActiveModel::Access#slice.
|
|
@@ -582,7 +599,7 @@ module ActiveRecord
|
|
|
582
599
|
#
|
|
583
600
|
# topic = Topic.new(title: "Budget", author_name: "Jason")
|
|
584
601
|
# topic.values_at(:title, :author_name)
|
|
585
|
-
# => ["Budget", "Jason"]
|
|
602
|
+
# # => ["Budget", "Jason"]
|
|
586
603
|
#
|
|
587
604
|
#--
|
|
588
605
|
# Implemented by ActiveModel::Access#values_at.
|
|
@@ -659,12 +676,14 @@ module ActiveRecord
|
|
|
659
676
|
# Sets the record to strict_loading mode. This will raise an error
|
|
660
677
|
# if the record tries to lazily load an association.
|
|
661
678
|
#
|
|
679
|
+
# NOTE: Strict loading is disabled during validation in order to let the record validate its association.
|
|
680
|
+
#
|
|
662
681
|
# user = User.first
|
|
663
682
|
# user.strict_loading! # => true
|
|
664
683
|
# user.address.city
|
|
665
|
-
# => ActiveRecord::StrictLoadingViolationError
|
|
684
|
+
# # => ActiveRecord::StrictLoadingViolationError
|
|
666
685
|
# user.comments.to_a
|
|
667
|
-
# => ActiveRecord::StrictLoadingViolationError
|
|
686
|
+
# # => ActiveRecord::StrictLoadingViolationError
|
|
668
687
|
#
|
|
669
688
|
# ==== Parameters
|
|
670
689
|
#
|
|
@@ -684,7 +703,7 @@ module ActiveRecord
|
|
|
684
703
|
# user.address.city # => "Tatooine"
|
|
685
704
|
# user.comments.to_a # => [#<Comment:0x00...]
|
|
686
705
|
# user.comments.first.ratings.to_a
|
|
687
|
-
# => ActiveRecord::StrictLoadingViolationError
|
|
706
|
+
# # => ActiveRecord::StrictLoadingViolationError
|
|
688
707
|
def strict_loading!(value = true, mode: :all)
|
|
689
708
|
unless [:all, :n_plus_one_only].include?(mode)
|
|
690
709
|
raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
|
|
@@ -706,11 +725,29 @@ module ActiveRecord
|
|
|
706
725
|
@strict_loading_mode == :all
|
|
707
726
|
end
|
|
708
727
|
|
|
709
|
-
#
|
|
728
|
+
# Prevents records from being written to the database:
|
|
729
|
+
#
|
|
730
|
+
# customer = Customer.new
|
|
731
|
+
# customer.readonly!
|
|
732
|
+
# customer.save # raises ActiveRecord::ReadOnlyRecord
|
|
733
|
+
#
|
|
734
|
+
# customer = Customer.first
|
|
735
|
+
# customer.readonly!
|
|
736
|
+
# customer.update(name: 'New Name') # raises ActiveRecord::ReadOnlyRecord
|
|
737
|
+
#
|
|
738
|
+
# Read-only records cannot be deleted from the database either:
|
|
710
739
|
#
|
|
711
740
|
# customer = Customer.first
|
|
712
741
|
# customer.readonly!
|
|
713
|
-
# customer.
|
|
742
|
+
# customer.destroy # raises ActiveRecord::ReadOnlyRecord
|
|
743
|
+
#
|
|
744
|
+
# Please, note that the objects themselves are still mutable in memory:
|
|
745
|
+
#
|
|
746
|
+
# customer = Customer.new
|
|
747
|
+
# customer.readonly!
|
|
748
|
+
# customer.name = 'New Name' # OK
|
|
749
|
+
#
|
|
750
|
+
# but you won't be able to persist the changes.
|
|
714
751
|
def readonly!
|
|
715
752
|
@readonly = true
|
|
716
753
|
end
|
|
@@ -719,21 +756,28 @@ module ActiveRecord
|
|
|
719
756
|
self.class.connection_handler
|
|
720
757
|
end
|
|
721
758
|
|
|
722
|
-
# Returns the
|
|
759
|
+
# Returns the attributes of the record as a nicely formatted string.
|
|
760
|
+
#
|
|
761
|
+
# Post.first.inspect
|
|
762
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
|
763
|
+
#
|
|
764
|
+
# The attributes can be limited by setting <tt>.attributes_for_inspect</tt>.
|
|
765
|
+
#
|
|
766
|
+
# Post.attributes_for_inspect = [:id, :title]
|
|
767
|
+
# Post.first.inspect
|
|
768
|
+
# #=> "#<Post id: 1, title: "Hello, World!">"
|
|
723
769
|
def inspect
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
inspection = if defined?(@attributes) && @attributes
|
|
727
|
-
attribute_names.filter_map do |name|
|
|
728
|
-
if _has_attribute?(name)
|
|
729
|
-
"#{name}: #{attribute_for_inspect(name)}"
|
|
730
|
-
end
|
|
731
|
-
end.join(", ")
|
|
732
|
-
else
|
|
733
|
-
"not initialized"
|
|
734
|
-
end
|
|
770
|
+
inspect_with_attributes(attributes_for_inspect)
|
|
771
|
+
end
|
|
735
772
|
|
|
736
|
-
|
|
773
|
+
# Returns all attributes of the record as a nicely formatted string,
|
|
774
|
+
# ignoring <tt>.attributes_for_inspect</tt>.
|
|
775
|
+
#
|
|
776
|
+
# Post.first.full_inspect
|
|
777
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
|
778
|
+
#
|
|
779
|
+
def full_inspect
|
|
780
|
+
inspect_with_attributes(all_attributes_for_inspect)
|
|
737
781
|
end
|
|
738
782
|
|
|
739
783
|
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
|
|
@@ -741,17 +785,17 @@ module ActiveRecord
|
|
|
741
785
|
def pretty_print(pp)
|
|
742
786
|
return super if custom_inspect_method_defined?
|
|
743
787
|
pp.object_address_group(self) do
|
|
744
|
-
if
|
|
745
|
-
attr_names =
|
|
788
|
+
if @attributes
|
|
789
|
+
attr_names = attributes_for_inspect.select { |name| _has_attribute?(name.to_s) }
|
|
746
790
|
pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
|
|
791
|
+
attr_name = attr_name.to_s
|
|
747
792
|
pp.breakable " "
|
|
748
793
|
pp.group(1) do
|
|
749
794
|
pp.text attr_name
|
|
750
795
|
pp.text ":"
|
|
751
796
|
pp.breakable
|
|
752
|
-
value =
|
|
753
|
-
|
|
754
|
-
pp.pp value
|
|
797
|
+
value = attribute_for_inspect(attr_name)
|
|
798
|
+
pp.text value
|
|
755
799
|
end
|
|
756
800
|
end
|
|
757
801
|
else
|
|
@@ -789,7 +833,6 @@ module ActiveRecord
|
|
|
789
833
|
@strict_loading_mode = :all
|
|
790
834
|
|
|
791
835
|
klass.define_attribute_methods
|
|
792
|
-
klass.generate_alias_attributes
|
|
793
836
|
end
|
|
794
837
|
|
|
795
838
|
def initialize_internals_callback
|
|
@@ -809,5 +852,30 @@ module ActiveRecord
|
|
|
809
852
|
def inspection_filter
|
|
810
853
|
self.class.inspection_filter
|
|
811
854
|
end
|
|
855
|
+
|
|
856
|
+
def inspect_with_attributes(attributes_to_list)
|
|
857
|
+
inspection = if @attributes
|
|
858
|
+
attributes_to_list.filter_map do |name|
|
|
859
|
+
name = name.to_s
|
|
860
|
+
if _has_attribute?(name)
|
|
861
|
+
"#{name}: #{attribute_for_inspect(name)}"
|
|
862
|
+
end
|
|
863
|
+
end.join(", ")
|
|
864
|
+
else
|
|
865
|
+
"not initialized"
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
"#<#{self.class} #{inspection}>"
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
def attributes_for_inspect
|
|
872
|
+
self.class.attributes_for_inspect == :all ? all_attributes_for_inspect : self.class.attributes_for_inspect
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
def all_attributes_for_inspect
|
|
876
|
+
return [] unless @attributes
|
|
877
|
+
|
|
878
|
+
attribute_names
|
|
879
|
+
end
|
|
812
880
|
end
|
|
813
881
|
end
|
|
@@ -7,6 +7,7 @@ module ActiveRecord
|
|
|
7
7
|
|
|
8
8
|
included do
|
|
9
9
|
class_attribute :_counter_cache_columns, instance_accessor: false, default: []
|
|
10
|
+
class_attribute :counter_cached_association_names, instance_writer: false, default: []
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
module ClassMethods
|
|
@@ -27,7 +28,7 @@ module ActiveRecord
|
|
|
27
28
|
# # For the Post with id #1, reset the comments_count
|
|
28
29
|
# Post.reset_counters(1, :comments)
|
|
29
30
|
#
|
|
30
|
-
# # Like above, but also touch the
|
|
31
|
+
# # Like above, but also touch the updated_at and/or updated_on
|
|
31
32
|
# # attributes.
|
|
32
33
|
# Post.reset_counters(1, :comments, touch: true)
|
|
33
34
|
def reset_counters(id, *counters, touch: nil)
|
|
@@ -181,14 +182,26 @@ module ActiveRecord
|
|
|
181
182
|
def counter_cache_column?(name) # :nodoc:
|
|
182
183
|
_counter_cache_columns.include?(name)
|
|
183
184
|
end
|
|
185
|
+
|
|
186
|
+
def load_schema! # :nodoc:
|
|
187
|
+
super
|
|
188
|
+
|
|
189
|
+
association_names = _reflections.filter_map do |name, reflection|
|
|
190
|
+
next unless reflection.belongs_to? && reflection.counter_cache_column
|
|
191
|
+
|
|
192
|
+
name.to_sym
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
self.counter_cached_association_names |= association_names
|
|
196
|
+
end
|
|
184
197
|
end
|
|
185
198
|
|
|
186
199
|
private
|
|
187
200
|
def _create_record(attribute_names = self.attribute_names)
|
|
188
201
|
id = super
|
|
189
202
|
|
|
190
|
-
|
|
191
|
-
association.increment_counters
|
|
203
|
+
counter_cached_association_names.each do |association_name|
|
|
204
|
+
association(association_name).increment_counters
|
|
192
205
|
end
|
|
193
206
|
|
|
194
207
|
id
|
|
@@ -198,7 +211,9 @@ module ActiveRecord
|
|
|
198
211
|
affected_rows = super
|
|
199
212
|
|
|
200
213
|
if affected_rows > 0
|
|
201
|
-
|
|
214
|
+
counter_cached_association_names.each do |association_name|
|
|
215
|
+
association = association(association_name)
|
|
216
|
+
|
|
202
217
|
unless destroyed_by_association && _foreign_keys_equal?(destroyed_by_association.foreign_key, association.reflection.foreign_key)
|
|
203
218
|
association.decrement_counters
|
|
204
219
|
end
|
|
@@ -208,12 +223,6 @@ module ActiveRecord
|
|
|
208
223
|
affected_rows
|
|
209
224
|
end
|
|
210
225
|
|
|
211
|
-
def each_counter_cached_associations
|
|
212
|
-
_reflections.each do |name, reflection|
|
|
213
|
-
yield association(name.to_sym) if reflection.belongs_to? && reflection.counter_cache_column
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
226
|
def _foreign_keys_equal?(fkey1, fkey2)
|
|
218
227
|
fkey1 == fkey2 || Array(fkey1).map(&:to_sym) == Array(fkey2).map(&:to_sym)
|
|
219
228
|
end
|
|
@@ -25,8 +25,7 @@ module ActiveRecord
|
|
|
25
25
|
def initialize(url)
|
|
26
26
|
raise "Database URL cannot be empty" if url.blank?
|
|
27
27
|
@uri = uri_parser.parse(url)
|
|
28
|
-
@adapter =
|
|
29
|
-
@adapter = "postgresql" if @adapter == "postgres"
|
|
28
|
+
@adapter = resolved_adapter
|
|
30
29
|
|
|
31
30
|
if @uri.opaque
|
|
32
31
|
@uri.opaque, @query = @uri.opaque.split("?", 2)
|
|
@@ -80,6 +79,14 @@ module ActiveRecord
|
|
|
80
79
|
end
|
|
81
80
|
end
|
|
82
81
|
|
|
82
|
+
def resolved_adapter
|
|
83
|
+
adapter = uri.scheme && @uri.scheme.tr("-", "_")
|
|
84
|
+
if adapter && ActiveRecord.protocol_adapters[adapter]
|
|
85
|
+
adapter = ActiveRecord.protocol_adapters[adapter]
|
|
86
|
+
end
|
|
87
|
+
adapter
|
|
88
|
+
end
|
|
89
|
+
|
|
83
90
|
# Returns name of the database.
|
|
84
91
|
def database_from_path
|
|
85
92
|
if @adapter == "sqlite3"
|