activerecord 7.1.5.2 → 8.1.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 +567 -2443
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +3 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- 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/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +18 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- 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/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +36 -5
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +268 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +8 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +250 -315
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- 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 +25 -61
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +20 -27
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +96 -68
- data/lib/active_record/autosave_association.rb +93 -58
- data/lib/active_record/base.rb +5 -7
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +136 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +44 -41
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
- data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +66 -0
- data/lib/active_record/connection_handling.rb +88 -46
- data/lib/active_record/core.rb +142 -58
- data/lib/active_record/counter_cache.rb +52 -18
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +28 -5
- data/lib/active_record/database_configurations/hash_config.rb +103 -41
- data/lib/active_record/database_configurations/url_config.rb +30 -1
- data/lib/active_record/database_configurations.rb +8 -4
- data/lib/active_record/delegated_type.rb +43 -19
- data/lib/active_record/dynamic_matchers.rb +56 -71
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +12 -12
- data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
- data/lib/active_record/encryption/encryptor.rb +58 -22
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- 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 +9 -2
- data/lib/active_record/enum.rb +57 -36
- data/lib/active_record/errors.rb +76 -26
- data/lib/active_record/explain.rb +14 -25
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +39 -35
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +5 -3
- data/lib/active_record/insert_all.rb +28 -20
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +15 -7
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -34
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +46 -14
- data/lib/active_record/migration/compatibility.rb +40 -25
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- 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 +119 -103
- data/lib/active_record/model_schema.rb +66 -78
- data/lib/active_record/nested_attributes.rb +17 -9
- data/lib/active_record/persistence.rb +161 -454
- data/lib/active_record/query_cache.rb +33 -15
- data/lib/active_record/query_logs.rb +106 -39
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +28 -16
- data/lib/active_record/railtie.rb +61 -74
- data/lib/active_record/railties/controller_runtime.rb +19 -5
- data/lib/active_record/railties/databases.rake +64 -78
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +147 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +153 -73
- data/lib/active_record/relation/calculations.rb +146 -96
- data/lib/active_record/relation/delegation.rb +30 -23
- data/lib/active_record/relation/finder_methods.rb +64 -34
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +25 -10
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +351 -124
- data/lib/active_record/relation/spawn_methods.rb +9 -25
- data/lib/active_record/relation/where_clause.rb +17 -30
- data/lib/active_record/relation.rb +590 -124
- data/lib/active_record/result.rb +131 -59
- data/lib/active_record/runtime_registry.rb +44 -21
- data/lib/active_record/sanitization.rb +33 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +66 -31
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +68 -20
- data/lib/active_record/statement_cache.rb +29 -25
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +7 -33
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +118 -90
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +17 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +123 -89
- data/lib/active_record/testing/query_assertions.rb +127 -0
- data/lib/active_record/timestamp.rb +6 -4
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +129 -0
- data/lib/active_record/transactions.rb +97 -18
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +12 -7
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +5 -4
- data/lib/active_record/validations/associated.rb +10 -4
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +203 -59
- data/lib/arel/alias_predication.rb +3 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +6 -5
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -4
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +14 -5
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -3
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +56 -12
- data/lib/arel/visitors/sqlite.rb +80 -8
- data/lib/arel/visitors/to_sql.rb +34 -37
- data/lib/arel.rb +10 -4
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +23 -14
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -167
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_record/associations/nested_error"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
# = Active Record Autosave Association
|
|
5
7
|
#
|
|
@@ -219,8 +221,10 @@ module ActiveRecord
|
|
|
219
221
|
if reflection.validate? && !method_defined?(validation_method)
|
|
220
222
|
if reflection.collection?
|
|
221
223
|
method = :validate_collection_association
|
|
224
|
+
elsif reflection.has_one?
|
|
225
|
+
method = :validate_has_one_association
|
|
222
226
|
else
|
|
223
|
-
method = :
|
|
227
|
+
method = :validate_belongs_to_association
|
|
224
228
|
end
|
|
225
229
|
|
|
226
230
|
define_non_cyclic_method(validation_method) { send(method, reflection) }
|
|
@@ -272,6 +276,16 @@ module ActiveRecord
|
|
|
272
276
|
new_record? || has_changes_to_save? || marked_for_destruction? || nested_records_changed_for_autosave?
|
|
273
277
|
end
|
|
274
278
|
|
|
279
|
+
def validating_belongs_to_for?(association)
|
|
280
|
+
@validating_belongs_to_for ||= {}
|
|
281
|
+
@validating_belongs_to_for[association]
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def autosaving_belongs_to_for?(association)
|
|
285
|
+
@autosaving_belongs_to_for ||= {}
|
|
286
|
+
@autosaving_belongs_to_for[association]
|
|
287
|
+
end
|
|
288
|
+
|
|
275
289
|
private
|
|
276
290
|
def init_internals
|
|
277
291
|
super
|
|
@@ -311,11 +325,33 @@ module ActiveRecord
|
|
|
311
325
|
end
|
|
312
326
|
|
|
313
327
|
# Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
|
|
314
|
-
# turned on for the association.
|
|
315
|
-
def
|
|
328
|
+
# turned on for the has_one association.
|
|
329
|
+
def validate_has_one_association(reflection)
|
|
316
330
|
association = association_instance_get(reflection.name)
|
|
317
331
|
record = association && association.reader
|
|
318
|
-
|
|
332
|
+
return unless record && (record.changed_for_autosave? || custom_validation_context?)
|
|
333
|
+
|
|
334
|
+
inverse_association = reflection.inverse_of && record.association(reflection.inverse_of.name)
|
|
335
|
+
return if inverse_association && (record.validating_belongs_to_for?(inverse_association) ||
|
|
336
|
+
record.autosaving_belongs_to_for?(inverse_association))
|
|
337
|
+
|
|
338
|
+
association_valid?(association, record)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
|
|
342
|
+
# turned on for the belongs_to association.
|
|
343
|
+
def validate_belongs_to_association(reflection)
|
|
344
|
+
association = association_instance_get(reflection.name)
|
|
345
|
+
record = association && association.reader
|
|
346
|
+
return unless record && (record.changed_for_autosave? || custom_validation_context?)
|
|
347
|
+
|
|
348
|
+
begin
|
|
349
|
+
@validating_belongs_to_for ||= {}
|
|
350
|
+
@validating_belongs_to_for[association] = true
|
|
351
|
+
association_valid?(association, record)
|
|
352
|
+
ensure
|
|
353
|
+
@validating_belongs_to_for[association] = false
|
|
354
|
+
end
|
|
319
355
|
end
|
|
320
356
|
|
|
321
357
|
# Validate the associated records if <tt>:validate</tt> or
|
|
@@ -324,7 +360,7 @@ module ActiveRecord
|
|
|
324
360
|
def validate_collection_association(reflection)
|
|
325
361
|
if association = association_instance_get(reflection.name)
|
|
326
362
|
if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave])
|
|
327
|
-
records.
|
|
363
|
+
records.each { |record| association_valid?(association, record) }
|
|
328
364
|
end
|
|
329
365
|
end
|
|
330
366
|
end
|
|
@@ -332,38 +368,33 @@ module ActiveRecord
|
|
|
332
368
|
# Returns whether or not the association is valid and applies any errors to
|
|
333
369
|
# the parent, <tt>self</tt>, if it wasn't. Skips any <tt>:autosave</tt>
|
|
334
370
|
# enabled records if they're marked_for_destruction? or destroyed.
|
|
335
|
-
def association_valid?(
|
|
336
|
-
return true if record.destroyed? || (
|
|
371
|
+
def association_valid?(association, record)
|
|
372
|
+
return true if record.destroyed? || (association.options[:autosave] && record.marked_for_destruction?)
|
|
337
373
|
|
|
338
374
|
context = validation_context if custom_validation_context?
|
|
375
|
+
return true if record.valid?(context)
|
|
339
376
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
377
|
+
if context || record.changed_for_autosave?
|
|
378
|
+
associated_errors = record.errors.objects
|
|
379
|
+
else
|
|
380
|
+
# If there are existing invalid records in the DB, we should still be able to reference them.
|
|
381
|
+
# Unless a record (no matter where in the association chain) is invalid and is being changed.
|
|
382
|
+
associated_errors = record.errors.objects.select { |error| error.is_a?(Associations::NestedError) }
|
|
383
|
+
end
|
|
343
384
|
|
|
344
|
-
|
|
345
|
-
|
|
385
|
+
if association.options[:autosave]
|
|
386
|
+
return if equal?(record)
|
|
346
387
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
else
|
|
355
|
-
errors.add(reflection.name)
|
|
356
|
-
end
|
|
388
|
+
associated_errors.each { |error|
|
|
389
|
+
errors.objects.append(
|
|
390
|
+
Associations::NestedError.new(association, error)
|
|
391
|
+
)
|
|
392
|
+
}
|
|
393
|
+
elsif associated_errors.any?
|
|
394
|
+
errors.add(association.reflection.name)
|
|
357
395
|
end
|
|
358
|
-
valid
|
|
359
|
-
end
|
|
360
396
|
|
|
361
|
-
|
|
362
|
-
if indexed_attribute
|
|
363
|
-
"#{reflection.name}[#{index}].#{attribute}"
|
|
364
|
-
else
|
|
365
|
-
"#{reflection.name}.#{attribute}"
|
|
366
|
-
end
|
|
397
|
+
errors.any?
|
|
367
398
|
end
|
|
368
399
|
|
|
369
400
|
# Is used as an around_save callback to check while saving a collection
|
|
@@ -444,33 +475,34 @@ module ActiveRecord
|
|
|
444
475
|
return unless association && association.loaded?
|
|
445
476
|
|
|
446
477
|
record = association.load_target
|
|
478
|
+
return unless record && !record.destroyed?
|
|
447
479
|
|
|
448
|
-
|
|
449
|
-
autosave = reflection.options[:autosave]
|
|
480
|
+
autosave = reflection.options[:autosave]
|
|
450
481
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
if (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record, primary_key_value)
|
|
458
|
-
unless reflection.through_reflection
|
|
459
|
-
foreign_key = Array(reflection.foreign_key)
|
|
460
|
-
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
|
482
|
+
if autosave && record.marked_for_destruction?
|
|
483
|
+
record.destroy
|
|
484
|
+
elsif autosave != false
|
|
485
|
+
primary_key = Array(compute_primary_key(reflection, self)).map(&:to_s)
|
|
486
|
+
primary_key_value = primary_key.map { |key| _read_attribute(key) }
|
|
487
|
+
return unless (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record, primary_key_value)
|
|
461
488
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
end
|
|
466
|
-
association.set_inverse_instance(record)
|
|
467
|
-
end
|
|
489
|
+
unless reflection.through_reflection
|
|
490
|
+
foreign_key = Array(reflection.foreign_key)
|
|
491
|
+
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
|
468
492
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
493
|
+
primary_key_foreign_key_pairs.each do |primary_key, foreign_key|
|
|
494
|
+
association_id = _read_attribute(primary_key)
|
|
495
|
+
record[foreign_key] = association_id unless record[foreign_key] == association_id
|
|
472
496
|
end
|
|
497
|
+
association.set_inverse_instance(record)
|
|
473
498
|
end
|
|
499
|
+
|
|
500
|
+
inverse_association = reflection.inverse_of && record.association(reflection.inverse_of.name)
|
|
501
|
+
return if inverse_association && record.autosaving_belongs_to_for?(inverse_association)
|
|
502
|
+
|
|
503
|
+
saved = record.save(validate: !autosave)
|
|
504
|
+
raise ActiveRecord::Rollback if !saved && autosave
|
|
505
|
+
saved
|
|
474
506
|
end
|
|
475
507
|
end
|
|
476
508
|
|
|
@@ -495,8 +527,7 @@ module ActiveRecord
|
|
|
495
527
|
return false unless reflection.inverse_of&.polymorphic?
|
|
496
528
|
|
|
497
529
|
class_name = record._read_attribute(reflection.inverse_of.foreign_type)
|
|
498
|
-
|
|
499
|
-
reflection.active_record != record.class.polymorphic_class_for(class_name)
|
|
530
|
+
reflection.active_record.polymorphic_name != class_name
|
|
500
531
|
end
|
|
501
532
|
|
|
502
533
|
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
|
@@ -515,7 +546,15 @@ module ActiveRecord
|
|
|
515
546
|
foreign_key.each { |key| self[key] = nil }
|
|
516
547
|
record.destroy
|
|
517
548
|
elsif autosave != false
|
|
518
|
-
saved =
|
|
549
|
+
saved = if record.new_record? || (autosave && record.changed_for_autosave?)
|
|
550
|
+
begin
|
|
551
|
+
@autosaving_belongs_to_for ||= {}
|
|
552
|
+
@autosaving_belongs_to_for[association] = true
|
|
553
|
+
record.save(validate: !autosave)
|
|
554
|
+
ensure
|
|
555
|
+
@autosaving_belongs_to_for[association] = false
|
|
556
|
+
end
|
|
557
|
+
end
|
|
519
558
|
|
|
520
559
|
if association.updated?
|
|
521
560
|
primary_key = Array(compute_primary_key(reflection, record)).map(&:to_s)
|
|
@@ -550,10 +589,6 @@ module ActiveRecord
|
|
|
550
589
|
end
|
|
551
590
|
end
|
|
552
591
|
|
|
553
|
-
def custom_validation_context?
|
|
554
|
-
validation_context && [:create, :update].exclude?(validation_context)
|
|
555
|
-
end
|
|
556
|
-
|
|
557
592
|
def _ensure_no_duplicate_errors
|
|
558
593
|
errors.uniq!
|
|
559
594
|
end
|
data/lib/active_record/base.rb
CHANGED
|
@@ -6,7 +6,7 @@ require "active_support/descendants_tracker"
|
|
|
6
6
|
require "active_support/time"
|
|
7
7
|
require "active_support/core_ext/class/subclasses"
|
|
8
8
|
require "active_record/log_subscriber"
|
|
9
|
-
require "active_record/
|
|
9
|
+
require "active_record/structured_event_subscriber"
|
|
10
10
|
require "active_record/relation/delegation"
|
|
11
11
|
require "active_record/attributes"
|
|
12
12
|
require "active_record/type_caster"
|
|
@@ -233,7 +233,7 @@ module ActiveRecord # :nodoc:
|
|
|
233
233
|
#
|
|
234
234
|
# Connections are usually created through
|
|
235
235
|
# {ActiveRecord::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection] and retrieved
|
|
236
|
-
# by ActiveRecord::Base.
|
|
236
|
+
# by ActiveRecord::Base.lease_connection. All classes inheriting from ActiveRecord::Base will use this
|
|
237
237
|
# connection. But you can also set a class-specific connection. For example, if Course is an
|
|
238
238
|
# ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
|
|
239
239
|
# and Course and all of its subclasses will use this connection instead.
|
|
@@ -256,13 +256,13 @@ module ActiveRecord # :nodoc:
|
|
|
256
256
|
# * AssociationTypeMismatch - The object assigned to the association wasn't of the type
|
|
257
257
|
# specified in the association definition.
|
|
258
258
|
# * AttributeAssignmentError - An error occurred while doing a mass assignment through the
|
|
259
|
-
# {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
|
|
259
|
+
# {ActiveRecord::Base#attributes=}[rdoc-ref:ActiveModel::AttributeAssignment#attributes=] method.
|
|
260
260
|
# You can inspect the +attribute+ property of the exception object to determine which attribute
|
|
261
261
|
# triggered the error.
|
|
262
262
|
# * ConnectionNotEstablished - No connection has been established.
|
|
263
263
|
# Use {ActiveRecord::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection] before querying.
|
|
264
264
|
# * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
|
|
265
|
-
# {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
|
|
265
|
+
# {ActiveRecord::Base#attributes=}[rdoc-ref:ActiveModel::AttributeAssignment#attributes=] method.
|
|
266
266
|
# The +errors+ property of this exception contains an array of
|
|
267
267
|
# AttributeAssignmentError
|
|
268
268
|
# objects that should be inspected to determine which attributes triggered the errors.
|
|
@@ -280,7 +280,7 @@ module ActiveRecord # :nodoc:
|
|
|
280
280
|
# So it's possible to assign a logger to the class through <tt>Base.logger=</tt> which will then be used by all
|
|
281
281
|
# instances in the current object space.
|
|
282
282
|
class Base
|
|
283
|
-
|
|
283
|
+
include ActiveModel::API
|
|
284
284
|
|
|
285
285
|
extend ActiveSupport::Benchmarkable
|
|
286
286
|
extend ActiveSupport::DescendantsTracker
|
|
@@ -304,7 +304,6 @@ module ActiveRecord # :nodoc:
|
|
|
304
304
|
include Scoping
|
|
305
305
|
include Sanitization
|
|
306
306
|
include AttributeAssignment
|
|
307
|
-
include ActiveModel::Conversion
|
|
308
307
|
include Integration
|
|
309
308
|
include Validations
|
|
310
309
|
include CounterCache
|
|
@@ -329,7 +328,6 @@ module ActiveRecord # :nodoc:
|
|
|
329
328
|
include TokenFor
|
|
330
329
|
include SignedId
|
|
331
330
|
include Suppressor
|
|
332
|
-
include Normalization
|
|
333
331
|
include Marshalling::Methods
|
|
334
332
|
|
|
335
333
|
self.param_delimiter = "_"
|
|
@@ -418,7 +418,7 @@ module ActiveRecord
|
|
|
418
418
|
|
|
419
419
|
def destroy # :nodoc:
|
|
420
420
|
@_destroy_callback_already_called ||= false
|
|
421
|
-
return if @_destroy_callback_already_called
|
|
421
|
+
return true if @_destroy_callback_already_called
|
|
422
422
|
@_destroy_callback_already_called = true
|
|
423
423
|
_run_destroy_callbacks { super }
|
|
424
424
|
rescue RecordNotDestroyed => e
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/json"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
module Coders # :nodoc:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
class JSON # :nodoc:
|
|
8
|
+
DEFAULT_OPTIONS = { escape: false }.freeze
|
|
9
|
+
|
|
10
|
+
def initialize(options = nil)
|
|
11
|
+
@options = options ? DEFAULT_OPTIONS.merge(options) : DEFAULT_OPTIONS
|
|
12
|
+
@encoder = ActiveSupport::JSON::Encoding.json_encoder.new(options)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def dump(obj)
|
|
16
|
+
@encoder.encode(obj)
|
|
8
17
|
end
|
|
9
18
|
|
|
10
|
-
def
|
|
11
|
-
ActiveSupport::JSON.decode(json) unless json.blank?
|
|
19
|
+
def load(json)
|
|
20
|
+
ActiveSupport::JSON.decode(json, @options) unless json.blank?
|
|
12
21
|
end
|
|
13
22
|
end
|
|
14
23
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "thread"
|
|
4
3
|
require "concurrent/map"
|
|
5
4
|
|
|
6
5
|
module ActiveRecord
|
|
@@ -55,31 +54,28 @@ module ActiveRecord
|
|
|
55
54
|
# about the model. The model needs to pass a connection specification name to the handler,
|
|
56
55
|
# in order to look up the correct connection pool.
|
|
57
56
|
class ConnectionHandler
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class StringConnectionName # :nodoc:
|
|
62
|
-
attr_reader :name
|
|
63
|
-
|
|
64
|
-
def initialize(name)
|
|
57
|
+
class ConnectionDescriptor # :nodoc:
|
|
58
|
+
def initialize(name, primary = false)
|
|
65
59
|
@name = name
|
|
60
|
+
@primary = primary
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def name
|
|
64
|
+
primary_class? ? "ActiveRecord::Base" : @name
|
|
66
65
|
end
|
|
67
66
|
|
|
68
67
|
def primary_class?
|
|
69
|
-
|
|
68
|
+
@primary
|
|
70
69
|
end
|
|
71
70
|
|
|
72
71
|
def current_preventing_writes
|
|
73
|
-
|
|
72
|
+
ActiveRecord::Base.preventing_writes?(@name)
|
|
74
73
|
end
|
|
75
74
|
end
|
|
76
75
|
|
|
77
76
|
def initialize
|
|
78
77
|
# These caches are keyed by pool_config.connection_name (PoolConfig#connection_name).
|
|
79
78
|
@connection_name_to_pool_manager = Concurrent::Map.new(initial_capacity: 2)
|
|
80
|
-
|
|
81
|
-
# Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred
|
|
82
|
-
ObjectSpace.define_finalizer self, FINALIZER
|
|
83
79
|
end
|
|
84
80
|
|
|
85
81
|
def prevent_writes # :nodoc:
|
|
@@ -94,22 +90,10 @@ module ActiveRecord
|
|
|
94
90
|
connection_name_to_pool_manager.keys
|
|
95
91
|
end
|
|
96
92
|
|
|
97
|
-
|
|
98
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
|
99
|
-
The `all_connection_pools` method is deprecated in favor of `connection_pool_list`.
|
|
100
|
-
Call `connection_pool_list(:all)` to get the same behavior as `all_connection_pools`.
|
|
101
|
-
MSG
|
|
102
|
-
connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# Returns the pools for a connection handler and given role. If +:all+ is passed,
|
|
93
|
+
# Returns the pools for a connection handler and given role. If +:all+ is passed,
|
|
106
94
|
# all pools belonging to the connection handler will be returned.
|
|
107
95
|
def connection_pool_list(role = nil)
|
|
108
|
-
if role.nil?
|
|
109
|
-
deprecation_for_pool_handling(__method__)
|
|
110
|
-
role = ActiveRecord::Base.current_role
|
|
111
|
-
connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
|
|
112
|
-
elsif role == :all
|
|
96
|
+
if role.nil? || role == :all
|
|
113
97
|
connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
|
|
114
98
|
else
|
|
115
99
|
connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
|
|
@@ -134,7 +118,7 @@ module ActiveRecord
|
|
|
134
118
|
pool_config = resolve_pool_config(config, owner_name, role, shard)
|
|
135
119
|
db_config = pool_config.db_config
|
|
136
120
|
|
|
137
|
-
pool_manager = set_pool_manager(pool_config.
|
|
121
|
+
pool_manager = set_pool_manager(pool_config.connection_descriptor)
|
|
138
122
|
|
|
139
123
|
# If there is an existing pool with the same values as the pool_config
|
|
140
124
|
# don't remove the connection. Connections should only be removed if we are
|
|
@@ -146,8 +130,8 @@ module ActiveRecord
|
|
|
146
130
|
# Update the pool_config's connection class if it differs. This is used
|
|
147
131
|
# for ensuring that ActiveRecord::Base and the primary_abstract_class use
|
|
148
132
|
# the same pool. Without this granular swapping will not work correctly.
|
|
149
|
-
if owner_name.primary_class? && (existing_pool_config.
|
|
150
|
-
existing_pool_config.
|
|
133
|
+
if owner_name.primary_class? && (existing_pool_config.connection_descriptor != owner_name)
|
|
134
|
+
existing_pool_config.connection_descriptor = owner_name
|
|
151
135
|
end
|
|
152
136
|
|
|
153
137
|
existing_pool_config.pool
|
|
@@ -156,7 +140,7 @@ module ActiveRecord
|
|
|
156
140
|
pool_manager.set_pool_config(role, shard, pool_config)
|
|
157
141
|
|
|
158
142
|
payload = {
|
|
159
|
-
connection_name: pool_config.
|
|
143
|
+
connection_name: pool_config.connection_descriptor.name,
|
|
160
144
|
role: role,
|
|
161
145
|
shard: shard,
|
|
162
146
|
config: db_config.configuration_hash
|
|
@@ -171,44 +155,25 @@ module ActiveRecord
|
|
|
171
155
|
# Returns true if there are any active connections among the connection
|
|
172
156
|
# pools that the ConnectionHandler is managing.
|
|
173
157
|
def active_connections?(role = nil)
|
|
174
|
-
if role.nil?
|
|
175
|
-
deprecation_for_pool_handling(__method__)
|
|
176
|
-
role = ActiveRecord::Base.current_role
|
|
177
|
-
end
|
|
178
|
-
|
|
179
158
|
each_connection_pool(role).any?(&:active_connection?)
|
|
180
159
|
end
|
|
181
160
|
|
|
182
|
-
# Returns any connections in use by the current thread back to the pool
|
|
183
|
-
# and also returns connections to the pool cached by threads that are no
|
|
184
|
-
# longer alive.
|
|
161
|
+
# Returns any connections in use by the current thread back to the pool.
|
|
185
162
|
def clear_active_connections!(role = nil)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
163
|
+
each_connection_pool(role).each do |pool|
|
|
164
|
+
pool.release_connection
|
|
165
|
+
pool.disable_query_cache!
|
|
189
166
|
end
|
|
190
|
-
|
|
191
|
-
each_connection_pool(role).each(&:release_connection)
|
|
192
167
|
end
|
|
193
168
|
|
|
194
|
-
# Clears
|
|
169
|
+
# Clears reloadable connection caches in all connection pools.
|
|
195
170
|
#
|
|
196
171
|
# See ConnectionPool#clear_reloadable_connections! for details.
|
|
197
172
|
def clear_reloadable_connections!(role = nil)
|
|
198
|
-
if role.nil?
|
|
199
|
-
deprecation_for_pool_handling(__method__)
|
|
200
|
-
role = ActiveRecord::Base.current_role
|
|
201
|
-
end
|
|
202
|
-
|
|
203
173
|
each_connection_pool(role).each(&:clear_reloadable_connections!)
|
|
204
174
|
end
|
|
205
175
|
|
|
206
176
|
def clear_all_connections!(role = nil)
|
|
207
|
-
if role.nil?
|
|
208
|
-
deprecation_for_pool_handling(__method__)
|
|
209
|
-
role = ActiveRecord::Base.current_role
|
|
210
|
-
end
|
|
211
|
-
|
|
212
177
|
each_connection_pool(role).each(&:disconnect!)
|
|
213
178
|
end
|
|
214
179
|
|
|
@@ -216,11 +181,6 @@ module ActiveRecord
|
|
|
216
181
|
#
|
|
217
182
|
# See ConnectionPool#flush! for details.
|
|
218
183
|
def flush_idle_connections!(role = nil)
|
|
219
|
-
if role.nil?
|
|
220
|
-
deprecation_for_pool_handling(__method__)
|
|
221
|
-
role = ActiveRecord::Base.current_role
|
|
222
|
-
end
|
|
223
|
-
|
|
224
184
|
each_connection_pool(role).each(&:flush!)
|
|
225
185
|
end
|
|
226
186
|
|
|
@@ -229,21 +189,8 @@ module ActiveRecord
|
|
|
229
189
|
# opened and set as the active connection for the class it was defined
|
|
230
190
|
# for (not necessarily the current class).
|
|
231
191
|
def retrieve_connection(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) # :nodoc:
|
|
232
|
-
pool = retrieve_connection_pool(connection_name, role: role, shard: shard)
|
|
233
|
-
|
|
234
|
-
unless pool
|
|
235
|
-
if shard != ActiveRecord::Base.default_shard
|
|
236
|
-
message = "No connection pool for '#{connection_name}' found for the '#{shard}' shard."
|
|
237
|
-
elsif role != ActiveRecord::Base.default_role
|
|
238
|
-
message = "No connection pool for '#{connection_name}' found for the '#{role}' role."
|
|
239
|
-
else
|
|
240
|
-
message = "No connection pool for '#{connection_name}' found."
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
raise ConnectionNotEstablished, message
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
pool.connection
|
|
192
|
+
pool = retrieve_connection_pool(connection_name, role: role, shard: shard, strict: true)
|
|
193
|
+
pool.lease_connection
|
|
247
194
|
end
|
|
248
195
|
|
|
249
196
|
# Returns true if a connection that's accessible to this class has
|
|
@@ -262,9 +209,29 @@ module ActiveRecord
|
|
|
262
209
|
# Retrieving the connection pool happens a lot, so we cache it in @connection_name_to_pool_manager.
|
|
263
210
|
# This makes retrieving the connection pool O(1) once the process is warm.
|
|
264
211
|
# When a connection is established or removed, we invalidate the cache.
|
|
265
|
-
def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
|
266
|
-
|
|
267
|
-
|
|
212
|
+
def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, strict: false)
|
|
213
|
+
pool_manager = get_pool_manager(connection_name)
|
|
214
|
+
pool = pool_manager&.get_pool_config(role, shard)&.pool
|
|
215
|
+
|
|
216
|
+
if strict && !pool
|
|
217
|
+
selector = [
|
|
218
|
+
("'#{shard}' shard" unless shard == ActiveRecord::Base.default_shard),
|
|
219
|
+
("'#{role}' role" unless role == ActiveRecord::Base.default_role),
|
|
220
|
+
].compact.join(" and ")
|
|
221
|
+
|
|
222
|
+
selector = [
|
|
223
|
+
(connection_name unless connection_name == "ActiveRecord::Base"),
|
|
224
|
+
selector.presence,
|
|
225
|
+
].compact.join(" with ")
|
|
226
|
+
|
|
227
|
+
selector = " for #{selector}" if selector.present?
|
|
228
|
+
|
|
229
|
+
message = "No database connection defined#{selector}."
|
|
230
|
+
|
|
231
|
+
raise ConnectionNotDefined.new(message, connection_name: connection_name, shard: shard, role: role)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
pool
|
|
268
235
|
end
|
|
269
236
|
|
|
270
237
|
private
|
|
@@ -276,31 +243,14 @@ module ActiveRecord
|
|
|
276
243
|
end
|
|
277
244
|
|
|
278
245
|
# Get the existing pool manager or initialize and assign a new one.
|
|
279
|
-
def set_pool_manager(
|
|
280
|
-
connection_name_to_pool_manager[
|
|
246
|
+
def set_pool_manager(connection_descriptor)
|
|
247
|
+
connection_name_to_pool_manager[connection_descriptor.name] ||= PoolManager.new
|
|
281
248
|
end
|
|
282
249
|
|
|
283
250
|
def pool_managers
|
|
284
251
|
connection_name_to_pool_manager.values
|
|
285
252
|
end
|
|
286
253
|
|
|
287
|
-
def deprecation_for_pool_handling(method)
|
|
288
|
-
roles = []
|
|
289
|
-
pool_managers.each do |pool_manager|
|
|
290
|
-
roles << pool_manager.role_names
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
if roles.flatten.uniq.count > 1
|
|
294
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
|
295
|
-
`#{method}` currently only applies to connection pools in the current
|
|
296
|
-
role (`#{ActiveRecord::Base.current_role}`). In Rails 7.2, this method
|
|
297
|
-
will apply to all known pools, regardless of role. To affect only those
|
|
298
|
-
connections belonging to a specific role, pass the role name as an
|
|
299
|
-
argument. To switch to the new behavior, pass `:all` as the role name.
|
|
300
|
-
MSG
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
|
|
304
254
|
def disconnect_pool_from_pool_manager(pool_manager, role, shard)
|
|
305
255
|
pool_config = pool_manager.remove_pool_config(role, shard)
|
|
306
256
|
|
|
@@ -322,42 +272,16 @@ module ActiveRecord
|
|
|
322
272
|
#
|
|
323
273
|
def resolve_pool_config(config, connection_name, role, shard)
|
|
324
274
|
db_config = Base.configurations.resolve(config)
|
|
325
|
-
|
|
275
|
+
db_config.validate!
|
|
326
276
|
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless db_config.adapter
|
|
327
|
-
|
|
328
|
-
# Require the adapter itself and give useful feedback about
|
|
329
|
-
# 1. Missing adapter gems and
|
|
330
|
-
# 2. Adapter gems' missing dependencies.
|
|
331
|
-
path_to_adapter = "active_record/connection_adapters/#{db_config.adapter}_adapter"
|
|
332
|
-
begin
|
|
333
|
-
require path_to_adapter
|
|
334
|
-
rescue LoadError => e
|
|
335
|
-
# We couldn't require the adapter itself. Raise an exception that
|
|
336
|
-
# points out config typos and missing gems.
|
|
337
|
-
if e.path == path_to_adapter
|
|
338
|
-
# We can assume that a non-builtin adapter was specified, so it's
|
|
339
|
-
# either misspelled or missing from Gemfile.
|
|
340
|
-
raise LoadError, "Could not load the '#{db_config.adapter}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
|
|
341
|
-
|
|
342
|
-
# Bubbled up from the adapter require. Prefix the exception message
|
|
343
|
-
# with some guidance about how to address it and reraise.
|
|
344
|
-
else
|
|
345
|
-
raise LoadError, "Error loading the '#{db_config.adapter}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
|
|
346
|
-
end
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
unless ActiveRecord::Base.respond_to?(db_config.adapter_method)
|
|
350
|
-
raise AdapterNotFound, "database configuration specifies nonexistent #{db_config.adapter} adapter"
|
|
351
|
-
end
|
|
352
|
-
|
|
353
277
|
ConnectionAdapters::PoolConfig.new(connection_name, db_config, role, shard)
|
|
354
278
|
end
|
|
355
279
|
|
|
356
280
|
def determine_owner_name(owner_name, config)
|
|
357
281
|
if owner_name.is_a?(String) || owner_name.is_a?(Symbol)
|
|
358
|
-
|
|
282
|
+
ConnectionDescriptor.new(owner_name.to_s)
|
|
359
283
|
elsif config.is_a?(Symbol)
|
|
360
|
-
|
|
284
|
+
ConnectionDescriptor.new(config.to_s)
|
|
361
285
|
else
|
|
362
286
|
owner_name
|
|
363
287
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "thread"
|
|
4
3
|
require "monitor"
|
|
5
4
|
|
|
6
5
|
module ActiveRecord
|
|
@@ -41,6 +40,14 @@ module ActiveRecord
|
|
|
41
40
|
end
|
|
42
41
|
end
|
|
43
42
|
|
|
43
|
+
# Add +element+ to the back of the queue. Never blocks.
|
|
44
|
+
def add_back(element)
|
|
45
|
+
synchronize do
|
|
46
|
+
@queue.unshift element
|
|
47
|
+
@cond.signal
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
44
51
|
# If +element+ is in the queue, remove and return it, or +nil+.
|
|
45
52
|
def delete(element)
|
|
46
53
|
synchronize do
|
|
@@ -55,6 +62,13 @@ module ActiveRecord
|
|
|
55
62
|
end
|
|
56
63
|
end
|
|
57
64
|
|
|
65
|
+
# Number of elements in the queue.
|
|
66
|
+
def size
|
|
67
|
+
synchronize do
|
|
68
|
+
@queue.size
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
58
72
|
# Remove the head of the queue.
|
|
59
73
|
#
|
|
60
74
|
# If +timeout+ is not given, remove and return the head of the
|
|
@@ -115,9 +129,7 @@ module ActiveRecord
|
|
|
115
129
|
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
116
130
|
elapsed = 0
|
|
117
131
|
loop do
|
|
118
|
-
|
|
119
|
-
@cond.wait(timeout - elapsed)
|
|
120
|
-
end
|
|
132
|
+
@cond.wait(timeout - elapsed)
|
|
121
133
|
|
|
122
134
|
return remove if any?
|
|
123
135
|
|