activerecord 7.1.3.4 → 7.2.2.1
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 +652 -2032
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +15 -8
- data/lib/active_record/associations/belongs_to_association.rb +18 -11
- 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 +11 -5
- 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 +3 -3
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations/has_one_association.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +10 -12
- 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 +62 -289
- 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/dirty.rb +2 -2
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +4 -16
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +89 -58
- data/lib/active_record/attributes.rb +61 -47
- data/lib/active_record/autosave_association.rb +17 -31
- data/lib/active_record/base.rb +2 -3
- 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 +270 -58
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +35 -18
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +190 -75
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +23 -10
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +38 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +73 -19
- 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 +8 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +16 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -32
- 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/cidr.rb +6 -0
- 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 +20 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +18 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +29 -24
- 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 +44 -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 +25 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +127 -77
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +32 -65
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +56 -41
- data/lib/active_record/core.rb +93 -40
- data/lib/active_record/counter_cache.rb +23 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +44 -36
- 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 +30 -6
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +3 -3
- data/lib/active_record/encryption/encrypted_attribute_type.rb +26 -6
- data/lib/active_record/encryption/encryptor.rb +18 -3
- 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/encryption/scheme.rb +8 -4
- data/lib/active_record/encryption.rb +2 -0
- data/lib/active_record/enum.rb +19 -2
- data/lib/active_record/errors.rb +46 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +17 -4
- data/lib/active_record/gem_version.rb +3 -3
- 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 +8 -7
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/message_pack.rb +2 -2
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +11 -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 +85 -76
- data/lib/active_record/model_schema.rb +38 -70
- data/lib/active_record/nested_attributes.rb +24 -5
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +32 -354
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +15 -0
- data/lib/active_record/query_logs_formatter.rb +1 -1
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +50 -68
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +42 -45
- data/lib/active_record/reflection.rb +106 -38
- 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 +96 -63
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +16 -2
- 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 +9 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +6 -1
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +245 -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 +7 -19
- data/lib/active_record/relation.rb +500 -66
- data/lib/active_record/result.rb +32 -45
- 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 +19 -9
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/signed_id.rb +20 -1
- 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 +98 -48
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +87 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +5 -3
- 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 +70 -14
- 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 +150 -41
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- 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/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- 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.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -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 -17
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +21 -15
@@ -125,11 +125,11 @@ module ActiveRecord
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def create_all
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
128
|
+
db_config = migration_connection.pool.db_config
|
129
|
+
|
130
|
+
each_local_configuration { |db_config| create(db_config) }
|
131
|
+
|
132
|
+
migration_class.establish_connection(db_config)
|
133
133
|
end
|
134
134
|
|
135
135
|
def setup_initial_database_yaml # :nodoc:
|
@@ -175,11 +175,12 @@ module ActiveRecord
|
|
175
175
|
|
176
176
|
def prepare_all
|
177
177
|
seed = false
|
178
|
+
dump_db_configs = []
|
178
179
|
|
179
180
|
each_current_configuration(env) do |db_config|
|
180
181
|
with_temporary_pool(db_config) do
|
181
182
|
begin
|
182
|
-
database_initialized =
|
183
|
+
database_initialized = migration_connection_pool.schema_migration.table_exists?
|
183
184
|
rescue ActiveRecord::NoDatabaseError
|
184
185
|
create(db_config)
|
185
186
|
retry
|
@@ -192,9 +193,27 @@ module ActiveRecord
|
|
192
193
|
|
193
194
|
seed = true
|
194
195
|
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
each_current_environment(env) do |environment|
|
200
|
+
db_configs_with_versions(environment).sort.each do |version, db_configs|
|
201
|
+
dump_db_configs |= db_configs
|
202
|
+
|
203
|
+
db_configs.each do |db_config|
|
204
|
+
with_temporary_pool(db_config) do
|
205
|
+
migrate(version)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
195
210
|
|
196
|
-
|
197
|
-
|
211
|
+
# Dump schema for databases that were migrated.
|
212
|
+
if ActiveRecord.dump_schema_after_migration
|
213
|
+
dump_db_configs.each do |db_config|
|
214
|
+
with_temporary_pool(db_config) do
|
215
|
+
dump_schema(db_config)
|
216
|
+
end
|
198
217
|
end
|
199
218
|
end
|
200
219
|
|
@@ -240,7 +259,7 @@ module ActiveRecord
|
|
240
259
|
|
241
260
|
check_target_version
|
242
261
|
|
243
|
-
|
262
|
+
migration_connection_pool.migration_context.migrate(target_version) do |migration|
|
244
263
|
if version.blank?
|
245
264
|
scope.blank? || scope == migration.scope
|
246
265
|
else
|
@@ -250,17 +269,17 @@ module ActiveRecord
|
|
250
269
|
Migration.write("No migrations ran. (using #{scope} scope)") if scope.present? && migrations_ran.empty?
|
251
270
|
end
|
252
271
|
|
253
|
-
|
272
|
+
migration_connection_pool.schema_cache.clear!
|
254
273
|
ensure
|
255
274
|
Migration.verbose = verbose_was
|
256
275
|
end
|
257
276
|
|
258
|
-
def db_configs_with_versions(
|
277
|
+
def db_configs_with_versions(environment = env) # :nodoc:
|
259
278
|
db_configs_with_versions = Hash.new { |h, k| h[k] = [] }
|
260
279
|
|
261
|
-
|
262
|
-
db_config =
|
263
|
-
versions_to_run =
|
280
|
+
with_temporary_pool_for_each(env: environment) do |pool|
|
281
|
+
db_config = pool.db_config
|
282
|
+
versions_to_run = pool.migration_context.pending_migration_versions
|
264
283
|
target_version = ActiveRecord::Tasks::DatabaseTasks.target_version
|
265
284
|
|
266
285
|
versions_to_run.each do |version|
|
@@ -273,15 +292,15 @@ module ActiveRecord
|
|
273
292
|
end
|
274
293
|
|
275
294
|
def migrate_status
|
276
|
-
unless
|
295
|
+
unless migration_connection_pool.schema_migration.table_exists?
|
277
296
|
Kernel.abort "Schema migrations table does not exist yet."
|
278
297
|
end
|
279
298
|
|
280
299
|
# output
|
281
|
-
puts "\ndatabase: #{
|
300
|
+
puts "\ndatabase: #{migration_connection_pool.db_config.database}\n\n"
|
282
301
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
283
302
|
puts "-" * 50
|
284
|
-
|
303
|
+
migration_connection_pool.migration_context.migrations_status.each do |status, version, name|
|
285
304
|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
286
305
|
end
|
287
306
|
puts
|
@@ -362,7 +381,7 @@ module ActiveRecord
|
|
362
381
|
raise ArgumentError, "unknown format #{format.inspect}"
|
363
382
|
end
|
364
383
|
|
365
|
-
|
384
|
+
migration_connection_pool.internal_metadata.create_table_and_set_flags(db_config.env_name, schema_sha1(file))
|
366
385
|
ensure
|
367
386
|
Migration.verbose = verbose_was
|
368
387
|
end
|
@@ -374,11 +393,12 @@ module ActiveRecord
|
|
374
393
|
|
375
394
|
return true unless file && File.exist?(file)
|
376
395
|
|
377
|
-
|
378
|
-
|
379
|
-
return false unless
|
396
|
+
with_temporary_pool(db_config) do |pool|
|
397
|
+
internal_metadata = pool.internal_metadata
|
398
|
+
return false unless internal_metadata.enabled?
|
399
|
+
return false unless internal_metadata.table_exists?
|
380
400
|
|
381
|
-
|
401
|
+
internal_metadata[:schema_sha1] == schema_sha1(file)
|
382
402
|
end
|
383
403
|
end
|
384
404
|
|
@@ -389,7 +409,7 @@ module ActiveRecord
|
|
389
409
|
|
390
410
|
with_temporary_pool(db_config, clobber: true) do
|
391
411
|
if schema_up_to_date?(db_config, format, file)
|
392
|
-
truncate_tables(db_config)
|
412
|
+
truncate_tables(db_config) unless ENV["SKIP_TEST_DATABASE_TRUNCATE"]
|
393
413
|
else
|
394
414
|
purge(db_config)
|
395
415
|
load_schema(db_config, format, file)
|
@@ -411,11 +431,11 @@ module ActiveRecord
|
|
411
431
|
case format
|
412
432
|
when :ruby
|
413
433
|
File.open(filename, "w:utf-8") do |file|
|
414
|
-
ActiveRecord::SchemaDumper.dump(
|
434
|
+
ActiveRecord::SchemaDumper.dump(migration_connection_pool, file)
|
415
435
|
end
|
416
436
|
when :sql
|
417
437
|
structure_dump(db_config, filename)
|
418
|
-
if
|
438
|
+
if migration_connection_pool.schema_migration.table_exists?
|
419
439
|
File.open(filename, "a") do |f|
|
420
440
|
f.puts migration_connection.dump_schema_information
|
421
441
|
f.print "\n"
|
@@ -437,14 +457,26 @@ module ActiveRecord
|
|
437
457
|
end
|
438
458
|
end
|
439
459
|
|
440
|
-
def cache_dump_filename(
|
441
|
-
|
442
|
-
|
460
|
+
def cache_dump_filename(db_config_or_name, schema_cache_path: nil)
|
461
|
+
if db_config_or_name.is_a?(DatabaseConfigurations::DatabaseConfig)
|
462
|
+
schema_cache_path ||
|
463
|
+
db_config_or_name.schema_cache_path ||
|
464
|
+
schema_cache_env ||
|
465
|
+
db_config_or_name.default_schema_cache_path(ActiveRecord::Tasks::DatabaseTasks.db_dir)
|
443
466
|
else
|
444
|
-
|
445
|
-
|
467
|
+
ActiveRecord.deprecator.warn(<<~MSG.squish)
|
468
|
+
Passing a database name to `cache_dump_filename` is deprecated and will be removed in Rails 8.0. Pass a
|
469
|
+
`ActiveRecord::DatabaseConfigurations::DatabaseConfig` object instead.
|
470
|
+
MSG
|
446
471
|
|
447
|
-
|
472
|
+
filename = if ActiveRecord::Base.configurations.primary?(db_config_or_name)
|
473
|
+
"schema_cache.yml"
|
474
|
+
else
|
475
|
+
"#{db_config_or_name}_schema_cache.yml"
|
476
|
+
end
|
477
|
+
|
478
|
+
schema_cache_path || schema_cache_env || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
|
479
|
+
end
|
448
480
|
end
|
449
481
|
|
450
482
|
def load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)
|
@@ -476,29 +508,29 @@ module ActiveRecord
|
|
476
508
|
# Dumps the schema cache in YAML format for the connection into the file
|
477
509
|
#
|
478
510
|
# ==== Examples
|
479
|
-
# ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.
|
480
|
-
def dump_schema_cache(
|
481
|
-
|
511
|
+
# ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.lease_connection, "tmp/schema_dump.yaml")
|
512
|
+
def dump_schema_cache(conn_or_pool, filename)
|
513
|
+
conn_or_pool.schema_cache.dump_to(filename)
|
482
514
|
end
|
483
515
|
|
484
516
|
def clear_schema_cache(filename)
|
485
517
|
FileUtils.rm_f filename, verbose: false
|
486
518
|
end
|
487
519
|
|
488
|
-
def
|
520
|
+
def with_temporary_pool_for_each(env: ActiveRecord::Tasks::DatabaseTasks.env, name: nil, clobber: false, &block) # :nodoc:
|
489
521
|
if name
|
490
522
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: env, name: name)
|
491
|
-
|
523
|
+
with_temporary_pool(db_config, clobber: clobber, &block)
|
492
524
|
else
|
493
525
|
ActiveRecord::Base.configurations.configs_for(env_name: env, name: name).each do |db_config|
|
494
|
-
|
526
|
+
with_temporary_pool(db_config, clobber: clobber, &block)
|
495
527
|
end
|
496
528
|
end
|
497
529
|
end
|
498
530
|
|
499
|
-
def with_temporary_connection(db_config, clobber: false) # :nodoc:
|
531
|
+
def with_temporary_connection(db_config, clobber: false, &block) # :nodoc:
|
500
532
|
with_temporary_pool(db_config, clobber: clobber) do |pool|
|
501
|
-
|
533
|
+
pool.with_connection(&block)
|
502
534
|
end
|
503
535
|
end
|
504
536
|
|
@@ -507,10 +539,25 @@ module ActiveRecord
|
|
507
539
|
end
|
508
540
|
|
509
541
|
def migration_connection # :nodoc:
|
510
|
-
migration_class.
|
542
|
+
migration_class.lease_connection
|
543
|
+
end
|
544
|
+
|
545
|
+
def migration_connection_pool # :nodoc:
|
546
|
+
migration_class.connection_pool
|
511
547
|
end
|
512
548
|
|
513
549
|
private
|
550
|
+
def schema_cache_env
|
551
|
+
if ENV["SCHEMA_CACHE"]
|
552
|
+
ActiveRecord.deprecator.warn(<<~MSG.squish)
|
553
|
+
Setting `ENV["SCHEMA_CACHE"]` is deprecated and will be removed in Rails 8.0.
|
554
|
+
Configure the `:schema_cache_path` in the database configuration instead.
|
555
|
+
MSG
|
556
|
+
|
557
|
+
nil
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
514
561
|
def with_temporary_pool(db_config, clobber: false)
|
515
562
|
original_db_config = migration_class.connection_db_config
|
516
563
|
pool = migration_class.connection_handler.establish_connection(db_config, clobber: clobber)
|
@@ -552,10 +599,7 @@ module ActiveRecord
|
|
552
599
|
end
|
553
600
|
|
554
601
|
def each_current_configuration(environment, name = nil)
|
555
|
-
|
556
|
-
environments << "test" if environment == "development" && !ENV["SKIP_TEST_DATABASE"] && !ENV["DATABASE_URL"]
|
557
|
-
|
558
|
-
environments.each do |env|
|
602
|
+
each_current_environment(environment) do |env|
|
559
603
|
configs_for(env_name: env).each do |db_config|
|
560
604
|
next if name && name != db_config.name
|
561
605
|
|
@@ -564,6 +608,12 @@ module ActiveRecord
|
|
564
608
|
end
|
565
609
|
end
|
566
610
|
|
611
|
+
def each_current_environment(environment, &block)
|
612
|
+
environments = [environment]
|
613
|
+
environments << "test" if environment == "development" && !ENV["SKIP_TEST_DATABASE"] && !ENV["DATABASE_URL"]
|
614
|
+
environments.each(&block)
|
615
|
+
end
|
616
|
+
|
567
617
|
def each_local_configuration
|
568
618
|
configs_for.each do |db_config|
|
569
619
|
next unless db_config.database
|
@@ -603,11 +653,11 @@ module ActiveRecord
|
|
603
653
|
|
604
654
|
def check_current_protected_environment!(db_config)
|
605
655
|
with_temporary_pool(db_config) do |pool|
|
606
|
-
|
607
|
-
current =
|
608
|
-
stored =
|
656
|
+
migration_context = pool.migration_context
|
657
|
+
current = migration_context.current_environment
|
658
|
+
stored = migration_context.last_stored_environment
|
609
659
|
|
610
|
-
if
|
660
|
+
if migration_context.protected_environment?
|
611
661
|
raise ActiveRecord::ProtectedEnvironmentError.new(stored)
|
612
662
|
end
|
613
663
|
|
@@ -66,11 +66,12 @@ module ActiveRecord
|
|
66
66
|
attr_reader :db_config, :root
|
67
67
|
|
68
68
|
def connection
|
69
|
-
ActiveRecord::Base.
|
69
|
+
ActiveRecord::Base.lease_connection
|
70
70
|
end
|
71
71
|
|
72
72
|
def establish_connection(config = db_config)
|
73
73
|
ActiveRecord::Base.establish_connection(config)
|
74
|
+
connection.connect!
|
74
75
|
end
|
75
76
|
|
76
77
|
def run_cmd(cmd, args, out)
|
@@ -13,6 +13,7 @@ module ActiveRecord
|
|
13
13
|
|
14
14
|
def after_teardown # :nodoc:
|
15
15
|
super
|
16
|
+
ensure
|
16
17
|
teardown_fixtures
|
17
18
|
end
|
18
19
|
|
@@ -52,20 +53,6 @@ module ActiveRecord
|
|
52
53
|
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
|
53
54
|
end
|
54
55
|
|
55
|
-
def fixture_path # :nodoc:
|
56
|
-
ActiveRecord.deprecator.warn(<<~WARNING)
|
57
|
-
TestFixtures.fixture_path is deprecated and will be removed in Rails 7.2. Use .fixture_paths instead.
|
58
|
-
If multiple fixture paths have been configured with .fixture_paths, then .fixture_path will just return
|
59
|
-
the first path.
|
60
|
-
WARNING
|
61
|
-
fixture_paths.first
|
62
|
-
end
|
63
|
-
|
64
|
-
def fixture_path=(path) # :nodoc:
|
65
|
-
ActiveRecord.deprecator.warn("TestFixtures.fixture_path= is deprecated and will be removed in Rails 7.2. Use .fixture_paths= instead.")
|
66
|
-
self.fixture_paths = Array(path)
|
67
|
-
end
|
68
|
-
|
69
56
|
def fixtures(*fixture_set_names)
|
70
57
|
if fixture_set_names.first == :all
|
71
58
|
raise StandardError, "No fixture path found. Please set `#{self}.fixture_paths`." if fixture_paths.blank?
|
@@ -78,7 +65,7 @@ module ActiveRecord
|
|
78
65
|
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
79
66
|
end
|
80
67
|
|
81
|
-
self.fixture_table_names
|
68
|
+
self.fixture_table_names = (fixture_table_names | fixture_set_names).sort
|
82
69
|
setup_fixture_accessors(fixture_set_names)
|
83
70
|
end
|
84
71
|
|
@@ -109,45 +96,76 @@ module ActiveRecord
|
|
109
96
|
end
|
110
97
|
end
|
111
98
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
fixture_paths.first
|
99
|
+
# Generic fixture accessor for fixture names that may conflict with other methods.
|
100
|
+
#
|
101
|
+
# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
|
102
|
+
# assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
|
103
|
+
def fixture(fixture_set_name, *fixture_names)
|
104
|
+
active_record_fixture(fixture_set_name, *fixture_names)
|
119
105
|
end
|
120
106
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
def setup_fixtures(config = ActiveRecord::Base)
|
127
|
-
if pre_loaded_fixtures && !use_transactional_tests
|
128
|
-
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
107
|
+
private
|
108
|
+
def run_in_transaction?
|
109
|
+
use_transactional_tests &&
|
110
|
+
!self.class.uses_transaction?(name)
|
129
111
|
end
|
130
112
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
113
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
114
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
115
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
116
|
+
end
|
117
|
+
|
118
|
+
@fixture_cache = {}
|
119
|
+
@fixture_cache_key = [self.class.fixture_table_names.dup, self.class.fixture_paths.dup, self.class.fixture_class_names.dup]
|
120
|
+
@fixture_connection_pools = []
|
121
|
+
@@already_loaded_fixtures ||= {}
|
122
|
+
@connection_subscriber = nil
|
123
|
+
@saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
|
124
|
+
|
125
|
+
if run_in_transaction?
|
126
|
+
# Load fixtures once and begin transaction.
|
127
|
+
@loaded_fixtures = @@already_loaded_fixtures[@fixture_cache_key]
|
128
|
+
unless @loaded_fixtures
|
129
|
+
@@already_loaded_fixtures.clear
|
130
|
+
@loaded_fixtures = @@already_loaded_fixtures[@fixture_cache_key] = load_fixtures(config)
|
131
|
+
end
|
136
132
|
|
137
|
-
|
138
|
-
if run_in_transaction?
|
139
|
-
if @@already_loaded_fixtures[self.class]
|
140
|
-
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
133
|
+
setup_transactional_fixtures
|
141
134
|
else
|
135
|
+
# Load fixtures for every test.
|
136
|
+
ActiveRecord::FixtureSet.reset_cache
|
137
|
+
invalidate_already_loaded_fixtures
|
142
138
|
@loaded_fixtures = load_fixtures(config)
|
143
|
-
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
144
139
|
end
|
145
140
|
|
141
|
+
# Instantiate fixtures for every test if requested.
|
142
|
+
instantiate_fixtures if use_instantiated_fixtures
|
143
|
+
end
|
144
|
+
|
145
|
+
def teardown_fixtures
|
146
|
+
# Rollback changes if a transaction is active.
|
147
|
+
if run_in_transaction?
|
148
|
+
teardown_transactional_fixtures
|
149
|
+
else
|
150
|
+
ActiveRecord::FixtureSet.reset_cache
|
151
|
+
invalidate_already_loaded_fixtures
|
152
|
+
end
|
153
|
+
|
154
|
+
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
155
|
+
end
|
156
|
+
|
157
|
+
def invalidate_already_loaded_fixtures
|
158
|
+
@@already_loaded_fixtures.clear
|
159
|
+
end
|
160
|
+
|
161
|
+
def setup_transactional_fixtures
|
162
|
+
setup_shared_connection_pool
|
163
|
+
|
146
164
|
# Begin transactions for connections already established
|
147
|
-
@
|
148
|
-
@
|
149
|
-
|
150
|
-
|
165
|
+
@fixture_connection_pools = ActiveRecord::Base.connection_handler.connection_pool_list(:writing)
|
166
|
+
@fixture_connection_pools.each do |pool|
|
167
|
+
pool.pin_connection!(lock_threads)
|
168
|
+
pool.lease_connection
|
151
169
|
end
|
152
170
|
|
153
171
|
# When connections are established in the future, begin a transaction too
|
@@ -156,59 +174,31 @@ module ActiveRecord
|
|
156
174
|
shard = payload[:shard] if payload.key?(:shard)
|
157
175
|
|
158
176
|
if connection_name
|
159
|
-
|
160
|
-
|
161
|
-
rescue ConnectionNotEstablished
|
162
|
-
connection = nil
|
163
|
-
end
|
164
|
-
|
165
|
-
if connection
|
177
|
+
pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(connection_name, shard: shard)
|
178
|
+
if pool
|
166
179
|
setup_shared_connection_pool
|
167
180
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
@
|
181
|
+
unless @fixture_connection_pools.include?(pool)
|
182
|
+
pool.pin_connection!(lock_threads)
|
183
|
+
pool.lease_connection
|
184
|
+
@fixture_connection_pools << pool
|
172
185
|
end
|
173
186
|
end
|
174
187
|
end
|
175
188
|
end
|
176
|
-
|
177
|
-
# Load fixtures for every test.
|
178
|
-
else
|
179
|
-
ActiveRecord::FixtureSet.reset_cache
|
180
|
-
@@already_loaded_fixtures[self.class] = nil
|
181
|
-
@loaded_fixtures = load_fixtures(config)
|
182
189
|
end
|
183
190
|
|
184
|
-
|
185
|
-
instantiate_fixtures if use_instantiated_fixtures
|
186
|
-
end
|
187
|
-
|
188
|
-
def teardown_fixtures
|
189
|
-
# Rollback changes if a transaction is active.
|
190
|
-
if run_in_transaction?
|
191
|
+
def teardown_transactional_fixtures
|
191
192
|
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
192
|
-
@
|
193
|
-
|
194
|
-
|
193
|
+
unless @fixture_connection_pools.map(&:unpin_connection!).all?
|
194
|
+
# Something caused the transaction to be committed or rolled back
|
195
|
+
# We can no longer trust the database is in a clean state.
|
196
|
+
@@already_loaded_fixtures.clear
|
195
197
|
end
|
196
|
-
@
|
198
|
+
@fixture_connection_pools.clear
|
197
199
|
teardown_shared_connection_pool
|
198
|
-
else
|
199
|
-
ActiveRecord::FixtureSet.reset_cache
|
200
200
|
end
|
201
201
|
|
202
|
-
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
203
|
-
end
|
204
|
-
|
205
|
-
def enlist_fixture_connections
|
206
|
-
setup_shared_connection_pool
|
207
|
-
|
208
|
-
ActiveRecord::Base.connection_handler.connection_pool_list(:writing).map(&:connection)
|
209
|
-
end
|
210
|
-
|
211
|
-
private
|
212
202
|
# Shares the writing connection pool with connections on
|
213
203
|
# other handlers.
|
214
204
|
#
|
@@ -271,22 +261,30 @@ module ActiveRecord
|
|
271
261
|
use_instantiated_fixtures != :no_instances
|
272
262
|
end
|
273
263
|
|
274
|
-
def method_missing(
|
275
|
-
if
|
276
|
-
|
264
|
+
def method_missing(method, ...)
|
265
|
+
if fixture_sets.key?(method.name)
|
266
|
+
active_record_fixture(method, ...)
|
277
267
|
else
|
278
268
|
super
|
279
269
|
end
|
280
270
|
end
|
281
271
|
|
282
|
-
def respond_to_missing?(
|
283
|
-
if include_private && fixture_sets.key?(name
|
272
|
+
def respond_to_missing?(method, include_private = false)
|
273
|
+
if include_private && fixture_sets.key?(method.name)
|
284
274
|
true
|
285
275
|
else
|
286
276
|
super
|
287
277
|
end
|
288
278
|
end
|
289
279
|
|
280
|
+
def active_record_fixture(fixture_set_name, *fixture_names)
|
281
|
+
if fs_name = fixture_sets[fixture_set_name.name]
|
282
|
+
access_fixture(fs_name, *fixture_names)
|
283
|
+
else
|
284
|
+
raise StandardError, "No fixture set named '#{fixture_set_name.inspect}'"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
290
288
|
def access_fixture(fs_name, *fixture_names)
|
291
289
|
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
292
290
|
return_single_record = fixture_names.size == 1
|