activerecord 7.2.2.1 → 8.1.2

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.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +564 -753
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +2 -1
  5. data/lib/active_record/associations/alias_tracker.rb +6 -4
  6. data/lib/active_record/associations/association.rb +35 -11
  7. data/lib/active_record/associations/belongs_to_association.rb +18 -2
  8. data/lib/active_record/associations/builder/association.rb +23 -11
  9. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  10. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  11. data/lib/active_record/associations/builder/has_one.rb +1 -1
  12. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  13. data/lib/active_record/associations/collection_association.rb +10 -8
  14. data/lib/active_record/associations/collection_proxy.rb +22 -4
  15. data/lib/active_record/associations/deprecation.rb +88 -0
  16. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  17. data/lib/active_record/associations/errors.rb +3 -0
  18. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  19. data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
  20. data/lib/active_record/associations/join_dependency.rb +4 -2
  21. data/lib/active_record/associations/preloader/association.rb +2 -2
  22. data/lib/active_record/associations/preloader/batch.rb +7 -1
  23. data/lib/active_record/associations/preloader/branch.rb +1 -0
  24. data/lib/active_record/associations/singular_association.rb +8 -3
  25. data/lib/active_record/associations.rb +192 -24
  26. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  27. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  28. data/lib/active_record/attribute_methods/query.rb +34 -0
  29. data/lib/active_record/attribute_methods/serialization.rb +17 -4
  30. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
  31. data/lib/active_record/attribute_methods.rb +24 -19
  32. data/lib/active_record/attributes.rb +40 -26
  33. data/lib/active_record/autosave_association.rb +91 -39
  34. data/lib/active_record/base.rb +3 -4
  35. data/lib/active_record/coders/json.rb +14 -5
  36. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
  37. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  38. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
  39. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
  40. data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
  41. data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
  42. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
  43. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
  45. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  46. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
  47. data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
  48. data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
  49. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
  50. data/lib/active_record/connection_adapters/column.rb +17 -4
  51. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  52. data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
  53. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  54. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  55. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
  56. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
  57. data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
  58. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  59. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  60. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  62. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  65. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  66. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  67. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
  68. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
  69. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
  70. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
  71. data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
  72. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
  73. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
  74. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  75. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
  76. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
  78. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  79. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
  80. data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
  81. data/lib/active_record/connection_adapters.rb +1 -56
  82. data/lib/active_record/connection_handling.rb +37 -10
  83. data/lib/active_record/core.rb +61 -25
  84. data/lib/active_record/counter_cache.rb +34 -9
  85. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  86. data/lib/active_record/database_configurations/database_config.rb +9 -1
  87. data/lib/active_record/database_configurations/hash_config.rb +67 -9
  88. data/lib/active_record/database_configurations/url_config.rb +13 -3
  89. data/lib/active_record/database_configurations.rb +7 -3
  90. data/lib/active_record/delegated_type.rb +19 -19
  91. data/lib/active_record/dynamic_matchers.rb +54 -69
  92. data/lib/active_record/encryption/config.rb +3 -1
  93. data/lib/active_record/encryption/encryptable_record.rb +9 -9
  94. data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
  95. data/lib/active_record/encryption/encryptor.rb +49 -28
  96. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  97. data/lib/active_record/encryption/scheme.rb +9 -2
  98. data/lib/active_record/enum.rb +46 -42
  99. data/lib/active_record/errors.rb +36 -12
  100. data/lib/active_record/explain.rb +1 -1
  101. data/lib/active_record/explain_registry.rb +51 -2
  102. data/lib/active_record/filter_attribute_handler.rb +73 -0
  103. data/lib/active_record/fixture_set/table_row.rb +19 -2
  104. data/lib/active_record/fixtures.rb +2 -4
  105. data/lib/active_record/future_result.rb +13 -9
  106. data/lib/active_record/gem_version.rb +3 -3
  107. data/lib/active_record/inheritance.rb +1 -1
  108. data/lib/active_record/insert_all.rb +12 -7
  109. data/lib/active_record/locking/optimistic.rb +8 -1
  110. data/lib/active_record/locking/pessimistic.rb +5 -0
  111. data/lib/active_record/log_subscriber.rb +3 -13
  112. data/lib/active_record/middleware/shard_selector.rb +34 -17
  113. data/lib/active_record/migration/command_recorder.rb +44 -11
  114. data/lib/active_record/migration/compatibility.rb +37 -24
  115. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  116. data/lib/active_record/migration.rb +50 -43
  117. data/lib/active_record/model_schema.rb +38 -13
  118. data/lib/active_record/nested_attributes.rb +6 -6
  119. data/lib/active_record/persistence.rb +162 -133
  120. data/lib/active_record/query_cache.rb +22 -15
  121. data/lib/active_record/query_logs.rb +104 -52
  122. data/lib/active_record/query_logs_formatter.rb +17 -28
  123. data/lib/active_record/querying.rb +12 -12
  124. data/lib/active_record/railtie.rb +37 -32
  125. data/lib/active_record/railties/controller_runtime.rb +11 -6
  126. data/lib/active_record/railties/databases.rake +26 -37
  127. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  128. data/lib/active_record/railties/job_runtime.rb +10 -11
  129. data/lib/active_record/reflection.rb +53 -21
  130. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  131. data/lib/active_record/relation/batches.rb +147 -73
  132. data/lib/active_record/relation/calculations.rb +80 -63
  133. data/lib/active_record/relation/delegation.rb +25 -15
  134. data/lib/active_record/relation/finder_methods.rb +54 -37
  135. data/lib/active_record/relation/merger.rb +8 -8
  136. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
  137. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  138. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  139. data/lib/active_record/relation/predicate_builder.rb +22 -7
  140. data/lib/active_record/relation/query_attribute.rb +4 -2
  141. data/lib/active_record/relation/query_methods.rb +156 -95
  142. data/lib/active_record/relation/spawn_methods.rb +7 -7
  143. data/lib/active_record/relation/where_clause.rb +10 -11
  144. data/lib/active_record/relation.rb +122 -80
  145. data/lib/active_record/result.rb +109 -24
  146. data/lib/active_record/runtime_registry.rb +42 -58
  147. data/lib/active_record/sanitization.rb +9 -6
  148. data/lib/active_record/schema_dumper.rb +47 -22
  149. data/lib/active_record/schema_migration.rb +2 -1
  150. data/lib/active_record/scoping/named.rb +5 -2
  151. data/lib/active_record/scoping.rb +0 -1
  152. data/lib/active_record/secure_token.rb +3 -3
  153. data/lib/active_record/signed_id.rb +47 -18
  154. data/lib/active_record/statement_cache.rb +24 -20
  155. data/lib/active_record/store.rb +51 -22
  156. data/lib/active_record/structured_event_subscriber.rb +85 -0
  157. data/lib/active_record/table_metadata.rb +6 -23
  158. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  159. data/lib/active_record/tasks/database_tasks.rb +85 -85
  160. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  161. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  162. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
  163. data/lib/active_record/test_databases.rb +14 -4
  164. data/lib/active_record/test_fixtures.rb +39 -2
  165. data/lib/active_record/testing/query_assertions.rb +8 -2
  166. data/lib/active_record/timestamp.rb +4 -2
  167. data/lib/active_record/token_for.rb +1 -1
  168. data/lib/active_record/transaction.rb +2 -5
  169. data/lib/active_record/transactions.rb +39 -16
  170. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  171. data/lib/active_record/type/internal/timezone.rb +7 -0
  172. data/lib/active_record/type/json.rb +15 -2
  173. data/lib/active_record/type/serialized.rb +11 -4
  174. data/lib/active_record/type/type_map.rb +1 -1
  175. data/lib/active_record/type_caster/connection.rb +2 -1
  176. data/lib/active_record/validations/associated.rb +1 -1
  177. data/lib/active_record/validations/uniqueness.rb +8 -8
  178. data/lib/active_record.rb +85 -50
  179. data/lib/arel/alias_predication.rb +2 -0
  180. data/lib/arel/collectors/bind.rb +2 -2
  181. data/lib/arel/collectors/sql_string.rb +1 -1
  182. data/lib/arel/collectors/substitute_binds.rb +2 -2
  183. data/lib/arel/crud.rb +8 -11
  184. data/lib/arel/delete_manager.rb +5 -0
  185. data/lib/arel/nodes/binary.rb +1 -1
  186. data/lib/arel/nodes/count.rb +2 -2
  187. data/lib/arel/nodes/delete_statement.rb +4 -2
  188. data/lib/arel/nodes/function.rb +4 -10
  189. data/lib/arel/nodes/named_function.rb +2 -2
  190. data/lib/arel/nodes/node.rb +2 -2
  191. data/lib/arel/nodes/sql_literal.rb +1 -1
  192. data/lib/arel/nodes/update_statement.rb +4 -2
  193. data/lib/arel/nodes.rb +0 -2
  194. data/lib/arel/select_manager.rb +13 -4
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/update_manager.rb +5 -0
  197. data/lib/arel/visitors/dot.rb +2 -3
  198. data/lib/arel/visitors/postgresql.rb +55 -0
  199. data/lib/arel/visitors/sqlite.rb +55 -8
  200. data/lib/arel/visitors/to_sql.rb +6 -22
  201. data/lib/arel.rb +3 -1
  202. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  203. metadata +17 -17
  204. data/lib/active_record/explain_subscriber.rb +0 -34
  205. data/lib/active_record/normalization.rb +0 -163
  206. 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
- INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :with, :with_recursive]
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, :klass, :loaded, :predicate_builder
71
+ attr_reader :table, :model, :loaded, :predicate_builder
72
72
  attr_accessor :skip_preloading_value
73
- alias :model :klass
73
+ alias :klass :model
74
74
  alias :loaded? :loaded
75
75
  alias :locked? :lock_value
76
76
 
77
- def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
78
- @klass = klass
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
- @delegate_to_klass = false
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 = klass._reflect_on_association(name)
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
@@ -265,7 +272,12 @@ module ActiveRecord
265
272
  # such situation.
266
273
  def create_or_find_by(attributes, &block)
267
274
  with_connection do |connection|
268
- transaction(requires_new: true) { create(attributes, &block) }
275
+ record = nil
276
+ transaction(requires_new: true) do
277
+ record = create(attributes, &block)
278
+ record._last_transaction_return_status || raise(ActiveRecord::Rollback)
279
+ end
280
+ record
269
281
  rescue ActiveRecord::RecordNotUnique
270
282
  if connection.transaction_open?
271
283
  where(attributes).lock.find_by!(attributes)
@@ -280,7 +292,12 @@ module ActiveRecord
280
292
  # is raised if the created record is invalid.
281
293
  def create_or_find_by!(attributes, &block)
282
294
  with_connection do |connection|
283
- transaction(requires_new: true) { create!(attributes, &block) }
295
+ record = nil
296
+ transaction(requires_new: true) do
297
+ record = create!(attributes, &block)
298
+ record._last_transaction_return_status || raise(ActiveRecord::Rollback)
299
+ end
300
+ record
284
301
  rescue ActiveRecord::RecordNotUnique
285
302
  if connection.transaction_open?
286
303
  where(attributes).lock.find_by!(attributes)
@@ -290,7 +307,7 @@ module ActiveRecord
290
307
  end
291
308
  end
292
309
 
293
- # Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
310
+ # Like #find_or_create_by, but calls {new}[rdoc-ref:Core.new]
294
311
  # instead of {create}[rdoc-ref:Persistence::ClassMethods#create].
295
312
  def find_or_initialize_by(attributes, &block)
296
313
  find_by(attributes) || new(attributes, &block)
@@ -430,14 +447,14 @@ module ActiveRecord
430
447
  # Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
431
448
  def cache_key(timestamp_column = "updated_at")
432
449
  @cache_keys ||= {}
433
- @cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
450
+ @cache_keys[timestamp_column] ||= model.collection_cache_key(self, timestamp_column)
434
451
  end
435
452
 
436
453
  def compute_cache_key(timestamp_column = :updated_at) # :nodoc:
437
454
  query_signature = ActiveSupport::Digest.hexdigest(to_sql)
438
- key = "#{klass.model_name.cache_key}/query-#{query_signature}"
455
+ key = "#{model.model_name.cache_key}/query-#{query_signature}"
439
456
 
440
- if collection_cache_versioning
457
+ if model.collection_cache_versioning
441
458
  key
442
459
  else
443
460
  "#{key}-#{compute_cache_version(timestamp_column)}"
@@ -456,7 +473,7 @@ module ActiveRecord
456
473
  #
457
474
  # SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
458
475
  def cache_version(timestamp_column = :updated_at)
459
- if collection_cache_versioning
476
+ if model.collection_cache_versioning
460
477
  @cache_versions ||= {}
461
478
  @cache_versions[timestamp_column] ||= compute_cache_version(timestamp_column)
462
479
  end
@@ -475,7 +492,7 @@ module ActiveRecord
475
492
 
476
493
  with_connection do |c|
477
494
  column = c.visitor.compile(table[timestamp_column])
478
- select_values = "COUNT(*) AS #{adapter_class.quote_column_name("size")}, MAX(%s) AS timestamp"
495
+ select_values = "COUNT(*) AS #{model.adapter_class.quote_column_name("size")}, MAX(%s) AS timestamp"
479
496
 
480
497
  if collection.has_limit_or_offset?
481
498
  query = collection.select("#{column} AS collection_cache_key_timestamp")
@@ -492,7 +509,7 @@ module ActiveRecord
492
509
  size, timestamp = c.select_rows(arel, nil).first
493
510
 
494
511
  if size
495
- column_type = klass.type_for_attribute(timestamp_column)
512
+ column_type = model.type_for_attribute(timestamp_column)
496
513
  timestamp = column_type.deserialize(timestamp)
497
514
  else
498
515
  size = 0
@@ -501,7 +518,7 @@ module ActiveRecord
501
518
  end
502
519
 
503
520
  if timestamp
504
- "#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
521
+ "#{size}-#{timestamp.utc.to_fs(model.cache_timestamp_format)}"
505
522
  else
506
523
  "#{size}"
507
524
  end
@@ -532,7 +549,7 @@ module ActiveRecord
532
549
  # Please check unscoped if you want to remove all previous scopes (including
533
550
  # the default_scope) during the execution of a block.
534
551
  def scoping(all_queries: nil, &block)
535
- registry = klass.scope_registry
552
+ registry = model.scope_registry
536
553
  if global_scope?(registry) && all_queries == false
537
554
  raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
538
555
  elsif already_in_scope?(registry)
@@ -543,11 +560,11 @@ module ActiveRecord
543
560
  end
544
561
 
545
562
  def _exec_scope(...) # :nodoc:
546
- @delegate_to_klass = true
547
- registry = klass.scope_registry
563
+ @delegate_to_model = true
564
+ registry = model.scope_registry
548
565
  _scoping(nil, registry) { instance_exec(...) || self }
549
566
  ensure
550
- @delegate_to_klass = false
567
+ @delegate_to_model = false
551
568
  end
552
569
 
553
570
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
@@ -583,31 +600,41 @@ module ActiveRecord
583
600
 
584
601
  return 0 if @none
585
602
 
603
+ invalid_methods = INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL.select do |method|
604
+ value = @values[method]
605
+ method == :distinct ? value : value&.any?
606
+ end
607
+ if invalid_methods.any?
608
+ ActiveRecord.deprecator.warn <<~MESSAGE
609
+ `#{invalid_methods.join(', ')}` is not supported by `update_all` and was never included in the generated query.
610
+
611
+ Calling `#{invalid_methods.join(', ')}` with `update_all` will raise an error in Rails 8.2.
612
+ MESSAGE
613
+ end
614
+
586
615
  if updates.is_a?(Hash)
587
- if klass.locking_enabled? &&
588
- !updates.key?(klass.locking_column) &&
589
- !updates.key?(klass.locking_column.to_sym)
590
- attr = table[klass.locking_column]
616
+ if model.locking_enabled? &&
617
+ !updates.key?(model.locking_column) &&
618
+ !updates.key?(model.locking_column.to_sym)
619
+ attr = table[model.locking_column]
591
620
  updates[attr.name] = _increment_attribute(attr)
592
621
  end
593
622
  values = _substitute_values(updates)
594
623
  else
595
- values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
624
+ values = Arel.sql(model.sanitize_sql_for_assignment(updates, table.name))
596
625
  end
597
626
 
598
- klass.with_connection do |c|
599
- arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
627
+ model.with_connection do |c|
628
+ arel = eager_loading? ? apply_join_dependency.arel : arel()
600
629
  arel.source.left = table
601
630
 
602
- group_values_arel_columns = arel_columns(group_values.uniq)
603
- having_clause_ast = having_clause.ast unless having_clause.empty?
604
- key = if klass.composite_primary_key?
631
+ key = if model.composite_primary_key?
605
632
  primary_key.map { |pk| table[pk] }
606
633
  else
607
634
  table[primary_key]
608
635
  end
609
- stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
610
- c.update(stmt, "#{klass} Update All").tap { reset }
636
+ stmt = arel.compile_update(values, key)
637
+ c.update(stmt, "#{model} Update All").tap { reset }
611
638
  end
612
639
  end
613
640
 
@@ -615,7 +642,7 @@ module ActiveRecord
615
642
  if id == :all
616
643
  each { |record| record.update(attributes) }
617
644
  else
618
- klass.update(id, attributes)
645
+ model.update(id, attributes)
619
646
  end
620
647
  end
621
648
 
@@ -623,7 +650,7 @@ module ActiveRecord
623
650
  if id == :all
624
651
  each { |record| record.update!(attributes) }
625
652
  else
626
- klass.update!(id, attributes)
653
+ model.update!(id, attributes)
627
654
  end
628
655
  end
629
656
 
@@ -813,7 +840,7 @@ module ActiveRecord
813
840
  #
814
841
  # [:returning]
815
842
  # (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
816
- # inserted records, which by default is the primary key.
843
+ # upserted records, which by default is the primary key.
817
844
  # Pass <tt>returning: %w[ id name ]</tt> for both id and name
818
845
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
819
846
  # clause entirely.
@@ -842,7 +869,9 @@ module ActiveRecord
842
869
  # Active Record's schema_cache.
843
870
  #
844
871
  # [:on_duplicate]
845
- # Configure the SQL update sentence that will be used in case of conflict.
872
+ # Configure the behavior that will be used in case of conflict. Use `:skip`
873
+ # to ignore any conflicts or provide a safe SQL fragment wrapped with
874
+ # `Arel.sql`.
846
875
  #
847
876
  # NOTE: If you use this option you must provide all the columns you want to update
848
877
  # by yourself.
@@ -929,7 +958,7 @@ module ActiveRecord
929
958
  names = touch if touch != true
930
959
  names = Array.wrap(names)
931
960
  options = names.extract_options!
932
- touch_updates = klass.touch_attributes_with_time(*names, **options)
961
+ touch_updates = model.touch_attributes_with_time(*names, **options)
933
962
  updates.merge!(touch_updates) unless touch_updates.empty?
934
963
  end
935
964
 
@@ -942,7 +971,7 @@ module ActiveRecord
942
971
  # If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
943
972
  # If no time argument is passed, the current time is used as default.
944
973
  #
945
- # === Examples
974
+ # ==== Examples
946
975
  #
947
976
  # # Touch all records
948
977
  # Person.all.touch_all
@@ -960,7 +989,7 @@ module ActiveRecord
960
989
  # Person.where(name: 'David').touch_all
961
990
  # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
962
991
  def touch_all(*names, time: nil)
963
- update_all klass.touch_attributes_with_time(*names, time: time)
992
+ update_all model.touch_attributes_with_time(*names, time: time)
964
993
  end
965
994
 
966
995
  # Destroys the records by instantiating each
@@ -993,7 +1022,7 @@ module ActiveRecord
993
1022
  #
994
1023
  # Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
995
1024
  #
996
- # Both calls delete the affected posts all at once with a single DELETE statement.
1025
+ # This call deletes the affected posts all at once with a single DELETE statement.
997
1026
  # If you need to destroy dependent associations or call your <tt>before_*</tt> or
998
1027
  # +after_destroy+ callbacks, use the #destroy_all method instead.
999
1028
  #
@@ -1004,7 +1033,7 @@ module ActiveRecord
1004
1033
  def delete_all
1005
1034
  return 0 if @none
1006
1035
 
1007
- invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
1036
+ invalid_methods = INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL.select do |method|
1008
1037
  value = @values[method]
1009
1038
  method == :distinct ? value : value&.any?
1010
1039
  end
@@ -1012,20 +1041,18 @@ module ActiveRecord
1012
1041
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
1013
1042
  end
1014
1043
 
1015
- klass.with_connection do |c|
1016
- arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
1044
+ model.with_connection do |c|
1045
+ arel = eager_loading? ? apply_join_dependency.arel : arel()
1017
1046
  arel.source.left = table
1018
1047
 
1019
- group_values_arel_columns = arel_columns(group_values.uniq)
1020
- having_clause_ast = having_clause.ast unless having_clause.empty?
1021
- key = if klass.composite_primary_key?
1048
+ key = if model.composite_primary_key?
1022
1049
  primary_key.map { |pk| table[pk] }
1023
1050
  else
1024
1051
  table[primary_key]
1025
1052
  end
1026
- stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
1053
+ stmt = arel.compile_delete(key)
1027
1054
 
1028
- c.delete(stmt, "#{klass} Delete All").tap { reset }
1055
+ c.delete(stmt, "#{model} Delete All").tap { reset }
1029
1056
  end
1030
1057
  end
1031
1058
 
@@ -1124,9 +1151,6 @@ module ActiveRecord
1124
1151
  # for queries to actually be executed concurrently. Otherwise it defaults to
1125
1152
  # executing them in the foreground.
1126
1153
  #
1127
- # +load_async+ will also fall back to executing in the foreground in the test environment when transactional
1128
- # fixtures are enabled.
1129
- #
1130
1154
  # If the query was actually executed in the background, the Active Record logs will show
1131
1155
  # it by prefixing the log line with <tt>ASYNC</tt>:
1132
1156
  #
@@ -1136,7 +1160,7 @@ module ActiveRecord
1136
1160
  return load if !c.async_enabled?
1137
1161
 
1138
1162
  unless loaded?
1139
- result = exec_main_query(async: c.current_transaction.closed?)
1163
+ result = exec_main_query(async: !c.current_transaction.joinable?)
1140
1164
 
1141
1165
  if result.is_a?(Array)
1142
1166
  @records = result
@@ -1150,6 +1174,16 @@ module ActiveRecord
1150
1174
  self
1151
1175
  end
1152
1176
 
1177
+ def then(&block) # :nodoc:
1178
+ if @future_result
1179
+ @future_result.then do
1180
+ yield self
1181
+ end
1182
+ else
1183
+ super
1184
+ end
1185
+ end
1186
+
1153
1187
  # Returns <tt>true</tt> if the relation was scheduled on the background
1154
1188
  # thread pool.
1155
1189
  def scheduled?
@@ -1180,7 +1214,7 @@ module ActiveRecord
1180
1214
  def reset
1181
1215
  @future_result&.cancel
1182
1216
  @future_result = nil
1183
- @delegate_to_klass = false
1217
+ @delegate_to_model = false
1184
1218
  @to_sql = @arel = @loaded = @should_eager_load = nil
1185
1219
  @offsets = @take = nil
1186
1220
  @cache_keys = nil
@@ -1200,7 +1234,7 @@ module ActiveRecord
1200
1234
  relation.to_sql
1201
1235
  end
1202
1236
  else
1203
- klass.with_connection do |conn|
1237
+ model.with_connection do |conn|
1204
1238
  conn.unprepared_statement { conn.to_sql(arel) }
1205
1239
  end
1206
1240
  end
@@ -1210,12 +1244,12 @@ module ActiveRecord
1210
1244
  #
1211
1245
  # User.where(name: 'Oscar').where_values_hash
1212
1246
  # # => {name: "Oscar"}
1213
- def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
1247
+ def where_values_hash(relation_table_name = model.table_name) # :nodoc:
1214
1248
  where_clause.to_h(relation_table_name)
1215
1249
  end
1216
1250
 
1217
1251
  def scope_for_create
1218
- hash = where_clause.to_h(klass.table_name, equality_only: true)
1252
+ hash = where_clause.to_h(model.table_name, equality_only: true)
1219
1253
  create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
1220
1254
  hash
1221
1255
  end
@@ -1261,6 +1295,10 @@ module ActiveRecord
1261
1295
  records.blank?
1262
1296
  end
1263
1297
 
1298
+ def readonly?
1299
+ readonly_value
1300
+ end
1301
+
1264
1302
  def values
1265
1303
  @values.dup
1266
1304
  end
@@ -1279,7 +1317,7 @@ module ActiveRecord
1279
1317
  end
1280
1318
 
1281
1319
  def empty_scope? # :nodoc:
1282
- @values == klass.unscoped.values
1320
+ @values == model.unscoped.values
1283
1321
  end
1284
1322
 
1285
1323
  def has_limit_or_offset? # :nodoc:
@@ -1287,7 +1325,7 @@ module ActiveRecord
1287
1325
  end
1288
1326
 
1289
1327
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
1290
- ActiveRecord::Associations::AliasTracker.create(connection_pool, table.name, joins, aliases)
1328
+ ActiveRecord::Associations::AliasTracker.create(model.connection_pool, table.name, joins, aliases)
1291
1329
  end
1292
1330
 
1293
1331
  class StrictLoadingScope # :nodoc:
@@ -1317,46 +1355,46 @@ module ActiveRecord
1317
1355
 
1318
1356
  private
1319
1357
  def already_in_scope?(registry)
1320
- @delegate_to_klass && registry.current_scope(klass, true)
1358
+ @delegate_to_model && registry.current_scope(model, true)
1321
1359
  end
1322
1360
 
1323
1361
  def global_scope?(registry)
1324
- registry.global_current_scope(klass, true)
1362
+ registry.global_current_scope(model, true)
1325
1363
  end
1326
1364
 
1327
1365
  def current_scope_restoring_block(&block)
1328
- current_scope = klass.current_scope(true)
1366
+ current_scope = model.current_scope(true)
1329
1367
  -> record do
1330
- klass.current_scope = current_scope
1368
+ model.current_scope = current_scope
1331
1369
  yield record if block_given?
1332
1370
  end
1333
1371
  end
1334
1372
 
1335
1373
  def _new(attributes, &block)
1336
- klass.new(attributes, &block)
1374
+ model.new(attributes, &block)
1337
1375
  end
1338
1376
 
1339
1377
  def _create(attributes, &block)
1340
- klass.create(attributes, &block)
1378
+ model.create(attributes, &block)
1341
1379
  end
1342
1380
 
1343
1381
  def _create!(attributes, &block)
1344
- klass.create!(attributes, &block)
1382
+ model.create!(attributes, &block)
1345
1383
  end
1346
1384
 
1347
1385
  def _scoping(scope, registry, all_queries = false)
1348
- previous = registry.current_scope(klass, true)
1349
- registry.set_current_scope(klass, scope)
1386
+ previous = registry.current_scope(model, true)
1387
+ registry.set_current_scope(model, scope)
1350
1388
 
1351
1389
  if all_queries
1352
- previous_global = registry.global_current_scope(klass, true)
1353
- registry.set_global_current_scope(klass, scope)
1390
+ previous_global = registry.global_current_scope(model, true)
1391
+ registry.set_global_current_scope(model, scope)
1354
1392
  end
1355
1393
  yield
1356
1394
  ensure
1357
- registry.set_current_scope(klass, previous)
1395
+ registry.set_current_scope(model, previous)
1358
1396
  if all_queries
1359
- registry.set_global_current_scope(klass, previous_global)
1397
+ registry.set_global_current_scope(model, previous_global)
1360
1398
  end
1361
1399
  end
1362
1400
 
@@ -1368,7 +1406,7 @@ module ActiveRecord
1368
1406
  value = Arel::Nodes::Grouping.new(value)
1369
1407
  end
1370
1408
  else
1371
- type = klass.type_for_attribute(attr.name)
1409
+ type = model.type_for_attribute(attr.name)
1372
1410
  value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
1373
1411
  end
1374
1412
  [attr, value]
@@ -1377,12 +1415,16 @@ module ActiveRecord
1377
1415
 
1378
1416
  def _increment_attribute(attribute, value = 1)
1379
1417
  bind = predicate_builder.build_bind_attribute(attribute.name, value.abs)
1380
- expr = table.coalesce(Arel::Nodes::UnqualifiedColumn.new(attribute), 0)
1418
+ expr = table.coalesce(attribute, 0)
1381
1419
  expr = value < 0 ? expr - bind : expr + bind
1382
1420
  expr.expr
1383
1421
  end
1384
1422
 
1385
1423
  def exec_queries(&block)
1424
+ if lock_value && model.current_preventing_writes
1425
+ raise ActiveRecord::ReadOnlyError, "Lock query attempted while in readonly mode"
1426
+ end
1427
+
1386
1428
  skip_query_cache_if_necessary do
1387
1429
  rows = if scheduled?
1388
1430
  future = @future_result
@@ -1415,20 +1457,20 @@ module ActiveRecord
1415
1457
  if where_clause.contradiction?
1416
1458
  [].freeze
1417
1459
  elsif eager_loading?
1418
- klass.with_connection do |c|
1460
+ model.with_connection do |c|
1419
1461
  apply_join_dependency do |relation, join_dependency|
1420
1462
  if relation.null_relation?
1421
1463
  [].freeze
1422
1464
  else
1423
1465
  relation = join_dependency.apply_column_aliases(relation)
1424
1466
  @_join_dependency = join_dependency
1425
- c.select_all(relation.arel, "SQL", async: async)
1467
+ c.select_all(relation.arel, "#{model.name} Eager Load", async: async)
1426
1468
  end
1427
1469
  end
1428
1470
  end
1429
1471
  else
1430
- klass.with_connection do |c|
1431
- klass._query_by_sql(c, arel, async: async)
1472
+ model.with_connection do |c|
1473
+ model._query_by_sql(c, arel, async: async)
1432
1474
  end
1433
1475
  end
1434
1476
  end
@@ -1441,13 +1483,13 @@ module ActiveRecord
1441
1483
  @_join_dependency = nil
1442
1484
  records
1443
1485
  else
1444
- klass._load_from_sql(rows, &block).freeze
1486
+ model._load_from_sql(rows, &block).freeze
1445
1487
  end
1446
1488
  end
1447
1489
 
1448
1490
  def skip_query_cache_if_necessary(&block)
1449
1491
  if skip_query_cache_value
1450
- uncached(&block)
1492
+ model.uncached(&block)
1451
1493
  else
1452
1494
  yield
1453
1495
  end