activerecord 7.2.4 → 8.1.4
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 +1013 -878
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/association.rb +69 -27
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +36 -8
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +7 -3
- data/lib/active_record/associations/collection_proxy.rb +26 -4
- 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 +3 -0
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency.rb +3 -2
- data/lib/active_record/associations/preloader/association.rb +3 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +18 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attributes.rb +3 -0
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/base.rb +1 -2
- data/lib/active_record/callbacks.rb +1 -2
- data/lib/active_record/coders/column_serializer.rb +1 -1
- data/lib/active_record/coders/json.rb +16 -6
- data/lib/active_record/coders/yaml_column.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +68 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +429 -93
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +148 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +27 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +32 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +124 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +129 -63
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +132 -65
- data/lib/active_record/connection_adapters/column.rb +14 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
- 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 -66
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -10
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +79 -61
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +46 -3
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- 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 +14 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +71 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +156 -68
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +78 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +15 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +104 -37
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +41 -66
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +15 -18
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +25 -2
- data/lib/active_record/core.rb +33 -17
- data/lib/active_record/counter_cache.rb +35 -8
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +74 -9
- data/lib/active_record/database_configurations/url_config.rb +15 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +5 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +8 -8
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encrypted_fixtures.rb +12 -7
- data/lib/active_record/encryption/encryptor.rb +28 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +33 -30
- data/lib/active_record/errors.rb +33 -9
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +76 -0
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +9 -4
- data/lib/active_record/insert_all.rb +14 -9
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +31 -29
- data/lib/active_record/message_pack.rb +13 -0
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +56 -13
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +48 -42
- data/lib/active_record/model_schema.rb +40 -15
- data/lib/active_record/nested_attributes.rb +14 -12
- data/lib/active_record/persistence.rb +163 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +100 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +35 -30
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -38
- 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 +54 -22
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +60 -43
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +73 -43
- data/lib/active_record/relation/merger.rb +12 -10
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -9
- 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 +23 -8
- data/lib/active_record/relation/query_attribute.rb +3 -1
- data/lib/active_record/relation/query_methods.rb +200 -96
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +2 -9
- data/lib/active_record/relation.rb +127 -87
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +17 -10
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/signed_id.rb +44 -16
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +53 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +83 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +4 -58
- data/lib/active_record/tasks/postgresql_database_tasks.rb +7 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +18 -4
- data/lib/active_record/test_fixtures.rb +52 -6
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +56 -32
- 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 +13 -2
- data/lib/active_record/type/serialized.rb +16 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +85 -50
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +6 -11
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +7 -2
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/dot.rb +0 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +4 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +15 -12
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -60,7 +60,7 @@ module ActiveRecord
|
|
|
60
60
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
|
61
61
|
|
|
62
62
|
CLAUSE_METHODS = [:where, :having, :from]
|
|
63
|
-
|
|
63
|
+
INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL = [:distinct, :with, :with_recursive]
|
|
64
64
|
|
|
65
65
|
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
|
|
66
66
|
|
|
@@ -68,19 +68,26 @@ module ActiveRecord
|
|
|
68
68
|
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
|
|
69
69
|
include SignedId::RelationMethods, TokenFor::RelationMethods
|
|
70
70
|
|
|
71
|
-
attr_reader :table, :
|
|
71
|
+
attr_reader :table, :model, :loaded, :predicate_builder
|
|
72
72
|
attr_accessor :skip_preloading_value
|
|
73
|
-
alias :
|
|
73
|
+
alias :klass :model
|
|
74
74
|
alias :loaded? :loaded
|
|
75
75
|
alias :locked? :lock_value
|
|
76
76
|
|
|
77
|
-
def initialize(
|
|
78
|
-
|
|
77
|
+
def initialize(model, table: nil, predicate_builder: nil, values: {})
|
|
78
|
+
if table
|
|
79
|
+
predicate_builder ||= model.predicate_builder.with(TableMetadata.new(model, table))
|
|
80
|
+
else
|
|
81
|
+
table = model.arel_table
|
|
82
|
+
predicate_builder ||= model.predicate_builder
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@model = model
|
|
79
86
|
@table = table
|
|
80
87
|
@values = values
|
|
81
88
|
@loaded = false
|
|
82
89
|
@predicate_builder = predicate_builder
|
|
83
|
-
@
|
|
90
|
+
@delegate_to_model = false
|
|
84
91
|
@future_result = nil
|
|
85
92
|
@records = nil
|
|
86
93
|
@async = false
|
|
@@ -93,7 +100,7 @@ module ActiveRecord
|
|
|
93
100
|
end
|
|
94
101
|
|
|
95
102
|
def bind_attribute(name, value) # :nodoc:
|
|
96
|
-
if reflection =
|
|
103
|
+
if reflection = model._reflect_on_association(name)
|
|
97
104
|
name = reflection.foreign_key
|
|
98
105
|
value = value.read_attribute(reflection.association_primary_key) unless value.nil?
|
|
99
106
|
end
|
|
@@ -273,7 +280,7 @@ module ActiveRecord
|
|
|
273
280
|
record
|
|
274
281
|
rescue ActiveRecord::RecordNotUnique
|
|
275
282
|
if connection.transaction_open?
|
|
276
|
-
|
|
283
|
+
rewhere(attributes).lock(connection.create_or_find_by_lock).take!
|
|
277
284
|
else
|
|
278
285
|
find_by!(attributes)
|
|
279
286
|
end
|
|
@@ -293,7 +300,7 @@ module ActiveRecord
|
|
|
293
300
|
record
|
|
294
301
|
rescue ActiveRecord::RecordNotUnique
|
|
295
302
|
if connection.transaction_open?
|
|
296
|
-
|
|
303
|
+
rewhere(attributes).lock(connection.create_or_find_by_lock).take!
|
|
297
304
|
else
|
|
298
305
|
find_by!(attributes)
|
|
299
306
|
end
|
|
@@ -374,10 +381,11 @@ module ActiveRecord
|
|
|
374
381
|
|
|
375
382
|
# Returns true if there are no records.
|
|
376
383
|
#
|
|
377
|
-
# When
|
|
378
|
-
#
|
|
384
|
+
# When an argument is given, returns true if no records match the argument
|
|
385
|
+
# via the case-equality operator (<tt>===</tt>).
|
|
379
386
|
#
|
|
380
|
-
# posts.none?(
|
|
387
|
+
# posts.none?(Post) # => true if posts is empty
|
|
388
|
+
# posts.none?(Comment) # => true
|
|
381
389
|
def none?(*args)
|
|
382
390
|
return true if @none
|
|
383
391
|
|
|
@@ -387,10 +395,12 @@ module ActiveRecord
|
|
|
387
395
|
|
|
388
396
|
# Returns true if there are any records.
|
|
389
397
|
#
|
|
390
|
-
# When a pattern argument is given, this method checks whether elements in
|
|
391
|
-
# the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
|
|
392
398
|
#
|
|
393
|
-
#
|
|
399
|
+
# When an argument is given, returns true if at least one records matches
|
|
400
|
+
# the argument via the case-equality operator (<tt>===</tt>).
|
|
401
|
+
#
|
|
402
|
+
# posts.any?(Post) # => true if at least one record
|
|
403
|
+
# posts.any?(Comment) # => false
|
|
394
404
|
def any?(*args)
|
|
395
405
|
return false if @none
|
|
396
406
|
|
|
@@ -400,10 +410,11 @@ module ActiveRecord
|
|
|
400
410
|
|
|
401
411
|
# Returns true if there is exactly one record.
|
|
402
412
|
#
|
|
403
|
-
# When
|
|
404
|
-
#
|
|
413
|
+
# When an argument is given, returns true if exactly one records matches the
|
|
414
|
+
# argument via the case-equality operator (<tt>===</tt>).
|
|
405
415
|
#
|
|
406
|
-
# posts.one?(Post) # => true
|
|
416
|
+
# posts.one?(Post) # => true if exactly one record
|
|
417
|
+
# posts.any?(Comment) # => false
|
|
407
418
|
def one?(*args)
|
|
408
419
|
return false if @none
|
|
409
420
|
|
|
@@ -440,14 +451,14 @@ module ActiveRecord
|
|
|
440
451
|
# Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
|
|
441
452
|
def cache_key(timestamp_column = "updated_at")
|
|
442
453
|
@cache_keys ||= {}
|
|
443
|
-
@cache_keys[timestamp_column] ||=
|
|
454
|
+
@cache_keys[timestamp_column] ||= model.collection_cache_key(self, timestamp_column)
|
|
444
455
|
end
|
|
445
456
|
|
|
446
457
|
def compute_cache_key(timestamp_column = :updated_at) # :nodoc:
|
|
447
458
|
query_signature = ActiveSupport::Digest.hexdigest(to_sql)
|
|
448
|
-
key = "#{
|
|
459
|
+
key = "#{model.model_name.cache_key}/query-#{query_signature}"
|
|
449
460
|
|
|
450
|
-
if collection_cache_versioning
|
|
461
|
+
if model.collection_cache_versioning
|
|
451
462
|
key
|
|
452
463
|
else
|
|
453
464
|
"#{key}-#{compute_cache_version(timestamp_column)}"
|
|
@@ -466,7 +477,7 @@ module ActiveRecord
|
|
|
466
477
|
#
|
|
467
478
|
# SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
|
|
468
479
|
def cache_version(timestamp_column = :updated_at)
|
|
469
|
-
if collection_cache_versioning
|
|
480
|
+
if model.collection_cache_versioning
|
|
470
481
|
@cache_versions ||= {}
|
|
471
482
|
@cache_versions[timestamp_column] ||= compute_cache_version(timestamp_column)
|
|
472
483
|
end
|
|
@@ -478,14 +489,14 @@ module ActiveRecord
|
|
|
478
489
|
if loaded?
|
|
479
490
|
size = records.size
|
|
480
491
|
if size > 0
|
|
481
|
-
timestamp = records.
|
|
492
|
+
timestamp = records.filter_map { |record| record.read_attribute(timestamp_column) }.max
|
|
482
493
|
end
|
|
483
494
|
else
|
|
484
495
|
collection = eager_loading? ? apply_join_dependency : self
|
|
485
496
|
|
|
486
497
|
with_connection do |c|
|
|
487
498
|
column = c.visitor.compile(table[timestamp_column])
|
|
488
|
-
select_values = "COUNT(*) AS #{adapter_class.quote_column_name("size")}, MAX(%s) AS timestamp"
|
|
499
|
+
select_values = "COUNT(*) AS #{model.adapter_class.quote_column_name("size")}, MAX(%s) AS timestamp"
|
|
489
500
|
|
|
490
501
|
if collection.has_limit_or_offset?
|
|
491
502
|
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
|
@@ -502,7 +513,7 @@ module ActiveRecord
|
|
|
502
513
|
size, timestamp = c.select_rows(arel, nil).first
|
|
503
514
|
|
|
504
515
|
if size
|
|
505
|
-
column_type =
|
|
516
|
+
column_type = model.type_for_attribute(timestamp_column)
|
|
506
517
|
timestamp = column_type.deserialize(timestamp)
|
|
507
518
|
else
|
|
508
519
|
size = 0
|
|
@@ -511,7 +522,7 @@ module ActiveRecord
|
|
|
511
522
|
end
|
|
512
523
|
|
|
513
524
|
if timestamp
|
|
514
|
-
"#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
|
|
525
|
+
"#{size}-#{timestamp.utc.to_fs(model.cache_timestamp_format)}"
|
|
515
526
|
else
|
|
516
527
|
"#{size}"
|
|
517
528
|
end
|
|
@@ -542,7 +553,7 @@ module ActiveRecord
|
|
|
542
553
|
# Please check unscoped if you want to remove all previous scopes (including
|
|
543
554
|
# the default_scope) during the execution of a block.
|
|
544
555
|
def scoping(all_queries: nil, &block)
|
|
545
|
-
registry =
|
|
556
|
+
registry = model.scope_registry
|
|
546
557
|
if global_scope?(registry) && all_queries == false
|
|
547
558
|
raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
|
|
548
559
|
elsif already_in_scope?(registry)
|
|
@@ -553,11 +564,11 @@ module ActiveRecord
|
|
|
553
564
|
end
|
|
554
565
|
|
|
555
566
|
def _exec_scope(...) # :nodoc:
|
|
556
|
-
@
|
|
557
|
-
registry =
|
|
567
|
+
@delegate_to_model = true
|
|
568
|
+
registry = model.scope_registry
|
|
558
569
|
_scoping(nil, registry) { instance_exec(...) || self }
|
|
559
570
|
ensure
|
|
560
|
-
@
|
|
571
|
+
@delegate_to_model = false
|
|
561
572
|
end
|
|
562
573
|
|
|
563
574
|
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
|
@@ -593,31 +604,41 @@ module ActiveRecord
|
|
|
593
604
|
|
|
594
605
|
return 0 if @none
|
|
595
606
|
|
|
607
|
+
invalid_methods = INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL.select do |method|
|
|
608
|
+
value = @values[method]
|
|
609
|
+
method == :distinct ? value : value&.any?
|
|
610
|
+
end
|
|
611
|
+
if invalid_methods.any?
|
|
612
|
+
ActiveRecord.deprecator.warn <<~MESSAGE
|
|
613
|
+
`#{invalid_methods.join(', ')}` is not supported by `update_all` and was never included in the generated query.
|
|
614
|
+
|
|
615
|
+
Calling `#{invalid_methods.join(', ')}` with `update_all` will raise an error in Rails 8.2.
|
|
616
|
+
MESSAGE
|
|
617
|
+
end
|
|
618
|
+
|
|
596
619
|
if updates.is_a?(Hash)
|
|
597
|
-
if
|
|
598
|
-
!updates.key?(
|
|
599
|
-
!updates.key?(
|
|
600
|
-
attr = table[
|
|
620
|
+
if model.locking_enabled? &&
|
|
621
|
+
!updates.key?(model.locking_column) &&
|
|
622
|
+
!updates.key?(model.locking_column.to_sym)
|
|
623
|
+
attr = table[model.locking_column]
|
|
601
624
|
updates[attr.name] = _increment_attribute(attr)
|
|
602
625
|
end
|
|
603
626
|
values = _substitute_values(updates)
|
|
604
627
|
else
|
|
605
|
-
values = Arel.sql(
|
|
628
|
+
values = Arel.sql(model.sanitize_sql_for_assignment(updates, table.name))
|
|
606
629
|
end
|
|
607
630
|
|
|
608
|
-
|
|
609
|
-
arel = eager_loading? ? apply_join_dependency.arel :
|
|
631
|
+
model.with_connection do |c|
|
|
632
|
+
arel = eager_loading? ? apply_join_dependency.arel : arel()
|
|
610
633
|
arel.source.left = table
|
|
611
634
|
|
|
612
|
-
|
|
613
|
-
having_clause_ast = having_clause.ast unless having_clause.empty?
|
|
614
|
-
key = if klass.composite_primary_key?
|
|
635
|
+
key = if model.composite_primary_key?
|
|
615
636
|
primary_key.map { |pk| table[pk] }
|
|
616
637
|
else
|
|
617
638
|
table[primary_key]
|
|
618
639
|
end
|
|
619
|
-
stmt = arel.compile_update(values, key
|
|
620
|
-
c.update(stmt, "#{
|
|
640
|
+
stmt = arel.compile_update(values, key)
|
|
641
|
+
c.update(stmt, "#{model} Update All").tap { reset }
|
|
621
642
|
end
|
|
622
643
|
end
|
|
623
644
|
|
|
@@ -625,7 +646,7 @@ module ActiveRecord
|
|
|
625
646
|
if id == :all
|
|
626
647
|
each { |record| record.update(attributes) }
|
|
627
648
|
else
|
|
628
|
-
|
|
649
|
+
model.update(id, attributes)
|
|
629
650
|
end
|
|
630
651
|
end
|
|
631
652
|
|
|
@@ -633,7 +654,7 @@ module ActiveRecord
|
|
|
633
654
|
if id == :all
|
|
634
655
|
each { |record| record.update!(attributes) }
|
|
635
656
|
else
|
|
636
|
-
|
|
657
|
+
model.update!(id, attributes)
|
|
637
658
|
end
|
|
638
659
|
end
|
|
639
660
|
|
|
@@ -852,7 +873,9 @@ module ActiveRecord
|
|
|
852
873
|
# Active Record's schema_cache.
|
|
853
874
|
#
|
|
854
875
|
# [:on_duplicate]
|
|
855
|
-
# Configure the
|
|
876
|
+
# Configure the behavior that will be used in case of conflict. Use `:skip`
|
|
877
|
+
# to ignore any conflicts or provide a safe SQL fragment wrapped with
|
|
878
|
+
# `Arel.sql`.
|
|
856
879
|
#
|
|
857
880
|
# NOTE: If you use this option you must provide all the columns you want to update
|
|
858
881
|
# by yourself.
|
|
@@ -939,7 +962,7 @@ module ActiveRecord
|
|
|
939
962
|
names = touch if touch != true
|
|
940
963
|
names = Array.wrap(names)
|
|
941
964
|
options = names.extract_options!
|
|
942
|
-
touch_updates =
|
|
965
|
+
touch_updates = model.touch_attributes_with_time(*names, **options)
|
|
943
966
|
updates.merge!(touch_updates) unless touch_updates.empty?
|
|
944
967
|
end
|
|
945
968
|
|
|
@@ -970,7 +993,7 @@ module ActiveRecord
|
|
|
970
993
|
# Person.where(name: 'David').touch_all
|
|
971
994
|
# # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
|
|
972
995
|
def touch_all(*names, time: nil)
|
|
973
|
-
update_all
|
|
996
|
+
update_all model.touch_attributes_with_time(*names, time: time)
|
|
974
997
|
end
|
|
975
998
|
|
|
976
999
|
# Destroys the records by instantiating each
|
|
@@ -1003,7 +1026,7 @@ module ActiveRecord
|
|
|
1003
1026
|
#
|
|
1004
1027
|
# Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
|
|
1005
1028
|
#
|
|
1006
|
-
#
|
|
1029
|
+
# This call deletes the affected posts all at once with a single DELETE statement.
|
|
1007
1030
|
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
|
|
1008
1031
|
# +after_destroy+ callbacks, use the #destroy_all method instead.
|
|
1009
1032
|
#
|
|
@@ -1014,7 +1037,7 @@ module ActiveRecord
|
|
|
1014
1037
|
def delete_all
|
|
1015
1038
|
return 0 if @none
|
|
1016
1039
|
|
|
1017
|
-
invalid_methods =
|
|
1040
|
+
invalid_methods = INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL.select do |method|
|
|
1018
1041
|
value = @values[method]
|
|
1019
1042
|
method == :distinct ? value : value&.any?
|
|
1020
1043
|
end
|
|
@@ -1022,20 +1045,18 @@ module ActiveRecord
|
|
|
1022
1045
|
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
|
1023
1046
|
end
|
|
1024
1047
|
|
|
1025
|
-
|
|
1026
|
-
arel = eager_loading? ? apply_join_dependency.arel :
|
|
1048
|
+
model.with_connection do |c|
|
|
1049
|
+
arel = eager_loading? ? apply_join_dependency.arel : arel()
|
|
1027
1050
|
arel.source.left = table
|
|
1028
1051
|
|
|
1029
|
-
|
|
1030
|
-
having_clause_ast = having_clause.ast unless having_clause.empty?
|
|
1031
|
-
key = if klass.composite_primary_key?
|
|
1052
|
+
key = if model.composite_primary_key?
|
|
1032
1053
|
primary_key.map { |pk| table[pk] }
|
|
1033
1054
|
else
|
|
1034
1055
|
table[primary_key]
|
|
1035
1056
|
end
|
|
1036
|
-
stmt = arel.compile_delete(key
|
|
1057
|
+
stmt = arel.compile_delete(key)
|
|
1037
1058
|
|
|
1038
|
-
c.delete(stmt, "#{
|
|
1059
|
+
c.delete(stmt, "#{model} Delete All").tap { reset }
|
|
1039
1060
|
end
|
|
1040
1061
|
end
|
|
1041
1062
|
|
|
@@ -1060,6 +1081,10 @@ module ActiveRecord
|
|
|
1060
1081
|
def delete(id_or_array)
|
|
1061
1082
|
return 0 if id_or_array.nil? || (id_or_array.is_a?(Array) && id_or_array.empty?)
|
|
1062
1083
|
|
|
1084
|
+
if model.composite_primary_key? && !id_or_array.first.is_a?(Array)
|
|
1085
|
+
id_or_array = [id_or_array]
|
|
1086
|
+
end
|
|
1087
|
+
|
|
1063
1088
|
where(model.primary_key => id_or_array).delete_all
|
|
1064
1089
|
end
|
|
1065
1090
|
|
|
@@ -1134,9 +1159,6 @@ module ActiveRecord
|
|
|
1134
1159
|
# for queries to actually be executed concurrently. Otherwise it defaults to
|
|
1135
1160
|
# executing them in the foreground.
|
|
1136
1161
|
#
|
|
1137
|
-
# +load_async+ will also fall back to executing in the foreground in the test environment when transactional
|
|
1138
|
-
# fixtures are enabled.
|
|
1139
|
-
#
|
|
1140
1162
|
# If the query was actually executed in the background, the Active Record logs will show
|
|
1141
1163
|
# it by prefixing the log line with <tt>ASYNC</tt>:
|
|
1142
1164
|
#
|
|
@@ -1146,7 +1168,7 @@ module ActiveRecord
|
|
|
1146
1168
|
return load if !c.async_enabled?
|
|
1147
1169
|
|
|
1148
1170
|
unless loaded?
|
|
1149
|
-
result = exec_main_query(async: c.current_transaction.
|
|
1171
|
+
result = exec_main_query(async: !c.current_transaction.joinable?)
|
|
1150
1172
|
|
|
1151
1173
|
if result.is_a?(Array)
|
|
1152
1174
|
@records = result
|
|
@@ -1160,6 +1182,16 @@ module ActiveRecord
|
|
|
1160
1182
|
self
|
|
1161
1183
|
end
|
|
1162
1184
|
|
|
1185
|
+
def then(&block) # :nodoc:
|
|
1186
|
+
if @future_result
|
|
1187
|
+
@future_result.then do
|
|
1188
|
+
yield self
|
|
1189
|
+
end
|
|
1190
|
+
else
|
|
1191
|
+
super
|
|
1192
|
+
end
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1163
1195
|
# Returns <tt>true</tt> if the relation was scheduled on the background
|
|
1164
1196
|
# thread pool.
|
|
1165
1197
|
def scheduled?
|
|
@@ -1190,7 +1222,7 @@ module ActiveRecord
|
|
|
1190
1222
|
def reset
|
|
1191
1223
|
@future_result&.cancel
|
|
1192
1224
|
@future_result = nil
|
|
1193
|
-
@
|
|
1225
|
+
@delegate_to_model = false
|
|
1194
1226
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
|
1195
1227
|
@offsets = @take = nil
|
|
1196
1228
|
@cache_keys = nil
|
|
@@ -1210,7 +1242,7 @@ module ActiveRecord
|
|
|
1210
1242
|
relation.to_sql
|
|
1211
1243
|
end
|
|
1212
1244
|
else
|
|
1213
|
-
|
|
1245
|
+
model.with_connection do |conn|
|
|
1214
1246
|
conn.unprepared_statement { conn.to_sql(arel) }
|
|
1215
1247
|
end
|
|
1216
1248
|
end
|
|
@@ -1220,12 +1252,12 @@ module ActiveRecord
|
|
|
1220
1252
|
#
|
|
1221
1253
|
# User.where(name: 'Oscar').where_values_hash
|
|
1222
1254
|
# # => {name: "Oscar"}
|
|
1223
|
-
def where_values_hash(relation_table_name =
|
|
1255
|
+
def where_values_hash(relation_table_name = model.table_name) # :nodoc:
|
|
1224
1256
|
where_clause.to_h(relation_table_name)
|
|
1225
1257
|
end
|
|
1226
1258
|
|
|
1227
1259
|
def scope_for_create
|
|
1228
|
-
hash = where_clause.to_h(
|
|
1260
|
+
hash = where_clause.to_h(model.table_name, equality_only: true)
|
|
1229
1261
|
create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
|
|
1230
1262
|
hash
|
|
1231
1263
|
end
|
|
@@ -1271,6 +1303,10 @@ module ActiveRecord
|
|
|
1271
1303
|
records.blank?
|
|
1272
1304
|
end
|
|
1273
1305
|
|
|
1306
|
+
def readonly?
|
|
1307
|
+
readonly_value
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1274
1310
|
def values
|
|
1275
1311
|
@values.dup
|
|
1276
1312
|
end
|
|
@@ -1289,7 +1325,7 @@ module ActiveRecord
|
|
|
1289
1325
|
end
|
|
1290
1326
|
|
|
1291
1327
|
def empty_scope? # :nodoc:
|
|
1292
|
-
@values ==
|
|
1328
|
+
@values == model.unscoped.values
|
|
1293
1329
|
end
|
|
1294
1330
|
|
|
1295
1331
|
def has_limit_or_offset? # :nodoc:
|
|
@@ -1297,7 +1333,7 @@ module ActiveRecord
|
|
|
1297
1333
|
end
|
|
1298
1334
|
|
|
1299
1335
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
|
1300
|
-
ActiveRecord::Associations::AliasTracker.create(connection_pool, table.name, joins, aliases)
|
|
1336
|
+
ActiveRecord::Associations::AliasTracker.create(model.connection_pool, table.name, joins, aliases)
|
|
1301
1337
|
end
|
|
1302
1338
|
|
|
1303
1339
|
class StrictLoadingScope # :nodoc:
|
|
@@ -1327,46 +1363,46 @@ module ActiveRecord
|
|
|
1327
1363
|
|
|
1328
1364
|
private
|
|
1329
1365
|
def already_in_scope?(registry)
|
|
1330
|
-
@
|
|
1366
|
+
@delegate_to_model && registry.current_scope(model, true)
|
|
1331
1367
|
end
|
|
1332
1368
|
|
|
1333
1369
|
def global_scope?(registry)
|
|
1334
|
-
registry.global_current_scope(
|
|
1370
|
+
registry.global_current_scope(model, true)
|
|
1335
1371
|
end
|
|
1336
1372
|
|
|
1337
1373
|
def current_scope_restoring_block(&block)
|
|
1338
|
-
current_scope =
|
|
1374
|
+
current_scope = model.current_scope(true)
|
|
1339
1375
|
-> record do
|
|
1340
|
-
|
|
1376
|
+
model.current_scope = current_scope
|
|
1341
1377
|
yield record if block_given?
|
|
1342
1378
|
end
|
|
1343
1379
|
end
|
|
1344
1380
|
|
|
1345
1381
|
def _new(attributes, &block)
|
|
1346
|
-
|
|
1382
|
+
model.new(attributes, &block)
|
|
1347
1383
|
end
|
|
1348
1384
|
|
|
1349
1385
|
def _create(attributes, &block)
|
|
1350
|
-
|
|
1386
|
+
model.create(attributes, &block)
|
|
1351
1387
|
end
|
|
1352
1388
|
|
|
1353
1389
|
def _create!(attributes, &block)
|
|
1354
|
-
|
|
1390
|
+
model.create!(attributes, &block)
|
|
1355
1391
|
end
|
|
1356
1392
|
|
|
1357
1393
|
def _scoping(scope, registry, all_queries = false)
|
|
1358
|
-
previous = registry.current_scope(
|
|
1359
|
-
registry.set_current_scope(
|
|
1394
|
+
previous = registry.current_scope(model, true)
|
|
1395
|
+
registry.set_current_scope(model, scope)
|
|
1360
1396
|
|
|
1361
1397
|
if all_queries
|
|
1362
|
-
previous_global = registry.global_current_scope(
|
|
1363
|
-
registry.set_global_current_scope(
|
|
1398
|
+
previous_global = registry.global_current_scope(model, true)
|
|
1399
|
+
registry.set_global_current_scope(model, scope)
|
|
1364
1400
|
end
|
|
1365
1401
|
yield
|
|
1366
1402
|
ensure
|
|
1367
|
-
registry.set_current_scope(
|
|
1403
|
+
registry.set_current_scope(model, previous)
|
|
1368
1404
|
if all_queries
|
|
1369
|
-
registry.set_global_current_scope(
|
|
1405
|
+
registry.set_global_current_scope(model, previous_global)
|
|
1370
1406
|
end
|
|
1371
1407
|
end
|
|
1372
1408
|
|
|
@@ -1378,7 +1414,7 @@ module ActiveRecord
|
|
|
1378
1414
|
value = Arel::Nodes::Grouping.new(value)
|
|
1379
1415
|
end
|
|
1380
1416
|
else
|
|
1381
|
-
type =
|
|
1417
|
+
type = model.type_for_attribute(attr.name)
|
|
1382
1418
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
|
1383
1419
|
end
|
|
1384
1420
|
[attr, value]
|
|
@@ -1387,12 +1423,16 @@ module ActiveRecord
|
|
|
1387
1423
|
|
|
1388
1424
|
def _increment_attribute(attribute, value = 1)
|
|
1389
1425
|
bind = predicate_builder.build_bind_attribute(attribute.name, value.abs)
|
|
1390
|
-
expr = table.coalesce(
|
|
1426
|
+
expr = table.coalesce(attribute, 0)
|
|
1391
1427
|
expr = value < 0 ? expr - bind : expr + bind
|
|
1392
1428
|
expr.expr
|
|
1393
1429
|
end
|
|
1394
1430
|
|
|
1395
1431
|
def exec_queries(&block)
|
|
1432
|
+
if lock_value && model.current_preventing_writes
|
|
1433
|
+
raise ActiveRecord::ReadOnlyError, "Lock query attempted while in readonly mode"
|
|
1434
|
+
end
|
|
1435
|
+
|
|
1396
1436
|
skip_query_cache_if_necessary do
|
|
1397
1437
|
rows = if scheduled?
|
|
1398
1438
|
future = @future_result
|
|
@@ -1425,20 +1465,20 @@ module ActiveRecord
|
|
|
1425
1465
|
if where_clause.contradiction?
|
|
1426
1466
|
[].freeze
|
|
1427
1467
|
elsif eager_loading?
|
|
1428
|
-
|
|
1468
|
+
model.with_connection do |c|
|
|
1429
1469
|
apply_join_dependency do |relation, join_dependency|
|
|
1430
1470
|
if relation.null_relation?
|
|
1431
1471
|
[].freeze
|
|
1432
1472
|
else
|
|
1433
1473
|
relation = join_dependency.apply_column_aliases(relation)
|
|
1434
1474
|
@_join_dependency = join_dependency
|
|
1435
|
-
c.select_all(relation.arel, "
|
|
1475
|
+
c.select_all(relation.arel, "#{model.name} Eager Load", async: async)
|
|
1436
1476
|
end
|
|
1437
1477
|
end
|
|
1438
1478
|
end
|
|
1439
1479
|
else
|
|
1440
|
-
|
|
1441
|
-
|
|
1480
|
+
model.with_connection do |c|
|
|
1481
|
+
model._query_by_sql(c, arel, async: async)
|
|
1442
1482
|
end
|
|
1443
1483
|
end
|
|
1444
1484
|
end
|
|
@@ -1451,13 +1491,13 @@ module ActiveRecord
|
|
|
1451
1491
|
@_join_dependency = nil
|
|
1452
1492
|
records
|
|
1453
1493
|
else
|
|
1454
|
-
|
|
1494
|
+
model._load_from_sql(rows, &block).freeze
|
|
1455
1495
|
end
|
|
1456
1496
|
end
|
|
1457
1497
|
|
|
1458
1498
|
def skip_query_cache_if_necessary(&block)
|
|
1459
1499
|
if skip_query_cache_value
|
|
1460
|
-
uncached(&block)
|
|
1500
|
+
model.uncached(&block)
|
|
1461
1501
|
else
|
|
1462
1502
|
yield
|
|
1463
1503
|
end
|