activerecord 6.1.4.1 → 7.0.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (240) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1203 -922
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +33 -17
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +34 -27
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/join_dependency.rb +6 -2
  25. data/lib/active_record/associations/preloader/association.rb +187 -55
  26. data/lib/active_record/associations/preloader/batch.rb +48 -0
  27. data/lib/active_record/associations/preloader/branch.rb +147 -0
  28. data/lib/active_record/associations/preloader/through_association.rb +49 -13
  29. data/lib/active_record/associations/preloader.rb +39 -113
  30. data/lib/active_record/associations/singular_association.rb +8 -2
  31. data/lib/active_record/associations/through_association.rb +3 -3
  32. data/lib/active_record/associations.rb +119 -90
  33. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  34. data/lib/active_record/attribute_assignment.rb +1 -1
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +49 -16
  37. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  38. data/lib/active_record/attribute_methods/query.rb +2 -2
  39. data/lib/active_record/attribute_methods/read.rb +7 -5
  40. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  42. data/lib/active_record/attribute_methods/write.rb +7 -10
  43. data/lib/active_record/attribute_methods.rb +13 -14
  44. data/lib/active_record/attributes.rb +24 -35
  45. data/lib/active_record/autosave_association.rb +8 -23
  46. data/lib/active_record/base.rb +19 -1
  47. data/lib/active_record/callbacks.rb +2 -2
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +38 -13
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +78 -22
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +38 -24
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +5 -1
  68. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  69. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -12
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  75. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  80. data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -50
  81. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +35 -19
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -107
  87. data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
  88. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +27 -19
  89. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +16 -14
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +89 -30
  92. data/lib/active_record/connection_adapters.rb +6 -5
  93. data/lib/active_record/connection_handling.rb +47 -53
  94. data/lib/active_record/core.rb +122 -132
  95. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  96. data/lib/active_record/database_configurations/database_config.rb +12 -9
  97. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  98. data/lib/active_record/database_configurations/url_config.rb +2 -2
  99. data/lib/active_record/database_configurations.rb +16 -32
  100. data/lib/active_record/delegated_type.rb +52 -11
  101. data/lib/active_record/destroy_association_async_job.rb +1 -1
  102. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  103. data/lib/active_record/dynamic_matchers.rb +1 -1
  104. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  105. data/lib/active_record/encryption/cipher.rb +53 -0
  106. data/lib/active_record/encryption/config.rb +44 -0
  107. data/lib/active_record/encryption/configurable.rb +61 -0
  108. data/lib/active_record/encryption/context.rb +35 -0
  109. data/lib/active_record/encryption/contexts.rb +72 -0
  110. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  111. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  112. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  113. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  114. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  115. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  116. data/lib/active_record/encryption/encryptor.rb +155 -0
  117. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  118. data/lib/active_record/encryption/errors.rb +15 -0
  119. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  120. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  121. data/lib/active_record/encryption/key.rb +28 -0
  122. data/lib/active_record/encryption/key_generator.rb +42 -0
  123. data/lib/active_record/encryption/key_provider.rb +46 -0
  124. data/lib/active_record/encryption/message.rb +33 -0
  125. data/lib/active_record/encryption/message_serializer.rb +90 -0
  126. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  127. data/lib/active_record/encryption/properties.rb +76 -0
  128. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  129. data/lib/active_record/encryption/scheme.rb +99 -0
  130. data/lib/active_record/encryption.rb +55 -0
  131. data/lib/active_record/enum.rb +49 -42
  132. data/lib/active_record/errors.rb +67 -4
  133. data/lib/active_record/explain_registry.rb +11 -6
  134. data/lib/active_record/fixture_set/file.rb +15 -1
  135. data/lib/active_record/fixture_set/table_row.rb +41 -6
  136. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  137. data/lib/active_record/fixtures.rb +17 -20
  138. data/lib/active_record/future_result.rb +139 -0
  139. data/lib/active_record/gem_version.rb +4 -4
  140. data/lib/active_record/inheritance.rb +55 -17
  141. data/lib/active_record/insert_all.rb +80 -14
  142. data/lib/active_record/integration.rb +4 -3
  143. data/lib/active_record/internal_metadata.rb +3 -5
  144. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  145. data/lib/active_record/locking/optimistic.rb +10 -9
  146. data/lib/active_record/locking/pessimistic.rb +9 -3
  147. data/lib/active_record/log_subscriber.rb +14 -3
  148. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  149. data/lib/active_record/middleware/database_selector.rb +8 -3
  150. data/lib/active_record/middleware/shard_selector.rb +60 -0
  151. data/lib/active_record/migration/command_recorder.rb +4 -4
  152. data/lib/active_record/migration/compatibility.rb +107 -3
  153. data/lib/active_record/migration/join_table.rb +1 -1
  154. data/lib/active_record/migration.rb +109 -79
  155. data/lib/active_record/model_schema.rb +45 -58
  156. data/lib/active_record/nested_attributes.rb +13 -12
  157. data/lib/active_record/no_touching.rb +3 -3
  158. data/lib/active_record/null_relation.rb +2 -6
  159. data/lib/active_record/persistence.rb +219 -52
  160. data/lib/active_record/query_cache.rb +2 -2
  161. data/lib/active_record/query_logs.rb +138 -0
  162. data/lib/active_record/querying.rb +15 -5
  163. data/lib/active_record/railtie.rb +127 -17
  164. data/lib/active_record/railties/controller_runtime.rb +1 -1
  165. data/lib/active_record/railties/databases.rake +66 -129
  166. data/lib/active_record/readonly_attributes.rb +11 -0
  167. data/lib/active_record/reflection.rb +67 -50
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  169. data/lib/active_record/relation/batches.rb +3 -3
  170. data/lib/active_record/relation/calculations.rb +43 -38
  171. data/lib/active_record/relation/delegation.rb +7 -7
  172. data/lib/active_record/relation/finder_methods.rb +31 -35
  173. data/lib/active_record/relation/merger.rb +20 -13
  174. data/lib/active_record/relation/predicate_builder.rb +1 -6
  175. data/lib/active_record/relation/query_attribute.rb +5 -11
  176. data/lib/active_record/relation/query_methods.rb +249 -61
  177. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  178. data/lib/active_record/relation/spawn_methods.rb +2 -2
  179. data/lib/active_record/relation/where_clause.rb +10 -19
  180. data/lib/active_record/relation.rb +184 -84
  181. data/lib/active_record/result.rb +17 -7
  182. data/lib/active_record/runtime_registry.rb +9 -13
  183. data/lib/active_record/sanitization.rb +11 -7
  184. data/lib/active_record/schema.rb +38 -23
  185. data/lib/active_record/schema_dumper.rb +25 -19
  186. data/lib/active_record/schema_migration.rb +4 -4
  187. data/lib/active_record/scoping/default.rb +61 -12
  188. data/lib/active_record/scoping/named.rb +3 -11
  189. data/lib/active_record/scoping.rb +64 -34
  190. data/lib/active_record/serialization.rb +1 -1
  191. data/lib/active_record/signed_id.rb +1 -1
  192. data/lib/active_record/suppressor.rb +11 -15
  193. data/lib/active_record/tasks/database_tasks.rb +120 -58
  194. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  195. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
  196. data/lib/active_record/test_databases.rb +1 -1
  197. data/lib/active_record/test_fixtures.rb +4 -4
  198. data/lib/active_record/timestamp.rb +3 -4
  199. data/lib/active_record/transactions.rb +9 -14
  200. data/lib/active_record/translation.rb +2 -2
  201. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  202. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  203. data/lib/active_record/type/internal/timezone.rb +2 -2
  204. data/lib/active_record/type/serialized.rb +1 -1
  205. data/lib/active_record/type/type_map.rb +17 -20
  206. data/lib/active_record/type.rb +1 -2
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/uniqueness.rb +1 -1
  209. data/lib/active_record.rb +204 -28
  210. data/lib/arel/attributes/attribute.rb +0 -8
  211. data/lib/arel/crud.rb +28 -22
  212. data/lib/arel/delete_manager.rb +18 -4
  213. data/lib/arel/filter_predications.rb +9 -0
  214. data/lib/arel/insert_manager.rb +2 -3
  215. data/lib/arel/nodes/casted.rb +1 -1
  216. data/lib/arel/nodes/delete_statement.rb +12 -13
  217. data/lib/arel/nodes/filter.rb +10 -0
  218. data/lib/arel/nodes/function.rb +1 -0
  219. data/lib/arel/nodes/insert_statement.rb +2 -2
  220. data/lib/arel/nodes/select_core.rb +2 -2
  221. data/lib/arel/nodes/select_statement.rb +2 -2
  222. data/lib/arel/nodes/update_statement.rb +8 -3
  223. data/lib/arel/nodes.rb +1 -0
  224. data/lib/arel/predications.rb +11 -3
  225. data/lib/arel/select_manager.rb +10 -4
  226. data/lib/arel/table.rb +0 -1
  227. data/lib/arel/tree_manager.rb +0 -12
  228. data/lib/arel/update_manager.rb +18 -4
  229. data/lib/arel/visitors/dot.rb +80 -90
  230. data/lib/arel/visitors/mysql.rb +8 -2
  231. data/lib/arel/visitors/postgresql.rb +0 -10
  232. data/lib/arel/visitors/to_sql.rb +58 -2
  233. data/lib/arel.rb +2 -1
  234. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  235. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  236. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  237. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  238. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  239. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  240. metadata +56 -11
@@ -10,6 +10,7 @@ module ActiveRecord
10
10
  included do
11
11
  class_attribute :_reflections, instance_writer: false, default: {}
12
12
  class_attribute :aggregate_reflections, instance_writer: false, default: {}
13
+ class_attribute :automatic_scope_inversing, instance_writer: false, default: false
13
14
  end
14
15
 
15
16
  class << self
@@ -115,7 +116,7 @@ module ActiveRecord
115
116
  reflections[association.to_s]
116
117
  end
117
118
 
118
- def _reflect_on_association(association) #:nodoc:
119
+ def _reflect_on_association(association) # :nodoc:
119
120
  _reflections[association.to_s]
120
121
  end
121
122
 
@@ -194,9 +195,9 @@ module ActiveRecord
194
195
  klass_scope
195
196
  end
196
197
 
197
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
198
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
198
199
  if scope
199
- [scope_for(build_scope(table, predicate_builder, klass))]
200
+ [scope_for(build_scope(table, predicate_builder, klass), record)]
200
201
  else
201
202
  []
202
203
  end
@@ -234,10 +235,13 @@ module ActiveRecord
234
235
  if has_inverse? && inverse_of.nil?
235
236
  raise InverseOfAssociationNotFoundError.new(self)
236
237
  end
238
+ if has_inverse? && inverse_of == self
239
+ raise InverseOfAssociationRecursiveError.new(self)
240
+ end
237
241
  end
238
242
  end
239
243
 
240
- # This shit is nasty. We need to avoid the following situation:
244
+ # We need to avoid the following situation:
241
245
  #
242
246
  # * An associated record is deleted via record.destroy
243
247
  # * Hence the callbacks run, and they find a belongs_to on the record with a
@@ -306,6 +310,12 @@ module ActiveRecord
306
310
  def primary_key(klass)
307
311
  klass.primary_key || raise(UnknownPrimaryKey.new(klass))
308
312
  end
313
+
314
+ def ensure_option_not_given_as_class!(option_name)
315
+ if options[option_name] && options[option_name].class == Class
316
+ raise ArgumentError, "A class was passed to `:#{option_name}` but we are expecting a string."
317
+ end
318
+ end
309
319
  end
310
320
 
311
321
  # Base class for AggregateReflection and AssociationReflection. Objects of
@@ -392,7 +402,7 @@ module ActiveRecord
392
402
 
393
403
  # Holds all the metadata about an aggregation as it was specified in the
394
404
  # Active Record class.
395
- class AggregateReflection < MacroReflection #:nodoc:
405
+ class AggregateReflection < MacroReflection # :nodoc:
396
406
  def mapping
397
407
  mapping = options[:mapping] || [name, name]
398
408
  mapping.first.is_a?(Array) ? mapping : [mapping]
@@ -401,12 +411,29 @@ module ActiveRecord
401
411
 
402
412
  # Holds all the metadata about an association as it was specified in the
403
413
  # Active Record class.
404
- class AssociationReflection < MacroReflection #:nodoc:
414
+ class AssociationReflection < MacroReflection # :nodoc:
405
415
  def compute_class(name)
406
416
  if polymorphic?
407
417
  raise ArgumentError, "Polymorphic associations do not support computing the class."
408
418
  end
409
- active_record.send(:compute_type, name)
419
+
420
+ msg = <<-MSG.squish
421
+ Rails couldn't find a valid model for #{name} association.
422
+ Please provide the :class_name option on the association declaration.
423
+ If :class_name is already provided, make sure it's an ActiveRecord::Base subclass.
424
+ MSG
425
+
426
+ begin
427
+ klass = active_record.send(:compute_type, name)
428
+
429
+ unless klass < ActiveRecord::Base
430
+ raise ArgumentError, msg
431
+ end
432
+
433
+ klass
434
+ rescue NameError
435
+ raise NameError, msg
436
+ end
410
437
  end
411
438
 
412
439
  attr_reader :type, :foreign_type
@@ -416,11 +443,8 @@ module ActiveRecord
416
443
  super
417
444
  @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
418
445
  @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
419
- @constructable = calculate_constructable(macro, options)
420
446
 
421
- if options[:class_name] && options[:class_name].class == Class
422
- raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
423
- end
447
+ ensure_option_not_given_as_class!(:class_name)
424
448
  end
425
449
 
426
450
  def association_scope_cache(klass, owner, &block)
@@ -431,10 +455,6 @@ module ActiveRecord
431
455
  klass.cached_find_by_statement(key, &block)
432
456
  end
433
457
 
434
- def constructable? # :nodoc:
435
- @constructable
436
- end
437
-
438
458
  def join_table
439
459
  @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
440
460
  end
@@ -467,18 +487,17 @@ module ActiveRecord
467
487
  check_validity_of_inverse!
468
488
  end
469
489
 
470
- def check_preloadable!
490
+ def check_eager_loadable!
471
491
  return unless scope
472
492
 
473
493
  unless scope.arity == 0
474
494
  raise ArgumentError, <<-MSG.squish
475
495
  The association scope '#{name}' is instance dependent (the scope
476
- block takes an argument). Preloading instance dependent scopes is
477
- not supported.
496
+ block takes an argument). Eager loading instance dependent scopes
497
+ is not supported.
478
498
  MSG
479
499
  end
480
500
  end
481
- alias :check_eager_loadable! :check_preloadable!
482
501
 
483
502
  def join_id_for(owner) # :nodoc:
484
503
  owner[join_foreign_key]
@@ -563,9 +582,6 @@ module ActiveRecord
563
582
  options[:polymorphic]
564
583
  end
565
584
 
566
- VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
567
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
568
-
569
585
  def add_as_source(seed)
570
586
  seed
571
587
  end
@@ -583,10 +599,6 @@ module ActiveRecord
583
599
  end
584
600
 
585
601
  private
586
- def calculate_constructable(macro, options)
587
- true
588
- end
589
-
590
602
  # Attempts to find the inverse association name automatically.
591
603
  # If it cannot find a suitable inverse association name, it returns
592
604
  # +nil+.
@@ -623,9 +635,10 @@ module ActiveRecord
623
635
  # with the current reflection's klass name.
624
636
  def valid_inverse_reflection?(reflection)
625
637
  reflection &&
638
+ reflection != self &&
626
639
  foreign_key == reflection.foreign_key &&
627
640
  klass <= reflection.active_record &&
628
- can_find_inverse_of_automatically?(reflection)
641
+ can_find_inverse_of_automatically?(reflection, true)
629
642
  end
630
643
 
631
644
  # Checks to see if the reflection doesn't have any options that prevent
@@ -634,14 +647,25 @@ module ActiveRecord
634
647
  # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
635
648
  # Third, we must not have options such as <tt>:foreign_key</tt>
636
649
  # which prevent us from correctly guessing the inverse association.
637
- #
638
- # Anything with a scope can additionally ruin our attempt at finding an
639
- # inverse, so we exclude reflections with scopes.
640
- def can_find_inverse_of_automatically?(reflection)
650
+ def can_find_inverse_of_automatically?(reflection, inverse_reflection = false)
641
651
  reflection.options[:inverse_of] != false &&
642
- VALID_AUTOMATIC_INVERSE_MACROS.include?(reflection.macro) &&
643
- !INVALID_AUTOMATIC_INVERSE_OPTIONS.any? { |opt| reflection.options[opt] } &&
652
+ !reflection.options[:through] &&
653
+ !reflection.options[:foreign_key] &&
654
+ scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
655
+ end
656
+
657
+ # Scopes on the potential inverse reflection prevent automatic
658
+ # <tt>inverse_of</tt>, since the scope could exclude the owner record
659
+ # we would inverse from. Scopes on the reflection itself allow for
660
+ # automatic <tt>inverse_of</tt> as long as
661
+ # <tt>config.active_record.automatic_scope_inversing<tt> is set to
662
+ # +true+ (the default for new applications).
663
+ def scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
664
+ if inverse_reflection
644
665
  !reflection.scope
666
+ else
667
+ !reflection.scope || reflection.klass.automatic_scope_inversing
668
+ end
645
669
  end
646
670
 
647
671
  def derive_class_name
@@ -656,7 +680,7 @@ module ActiveRecord
656
680
  elsif options[:as]
657
681
  "#{options[:as]}_id"
658
682
  else
659
- active_record.name.foreign_key
683
+ active_record.model_name.to_s.foreign_key
660
684
  end
661
685
  end
662
686
 
@@ -691,11 +715,6 @@ module ActiveRecord
691
715
  Associations::HasOneAssociation
692
716
  end
693
717
  end
694
-
695
- private
696
- def calculate_constructable(macro, options)
697
- !options[:through]
698
- end
699
718
  end
700
719
 
701
720
  class BelongsToReflection < AssociationReflection # :nodoc:
@@ -733,13 +752,9 @@ module ActiveRecord
733
752
  end
734
753
 
735
754
  private
736
- def can_find_inverse_of_automatically?(_)
755
+ def can_find_inverse_of_automatically?(*)
737
756
  !polymorphic? && super
738
757
  end
739
-
740
- def calculate_constructable(macro, options)
741
- !polymorphic?
742
- end
743
758
  end
744
759
 
745
760
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
@@ -752,7 +767,7 @@ module ActiveRecord
752
767
 
753
768
  # Holds all the metadata about a :through association as it was specified
754
769
  # in the Active Record class.
755
- class ThroughReflection < AbstractReflection #:nodoc:
770
+ class ThroughReflection < AbstractReflection # :nodoc:
756
771
  delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
757
772
  :active_record_primary_key, :join_foreign_key, to: :source_reflection
758
773
 
@@ -760,6 +775,8 @@ module ActiveRecord
760
775
  @delegate_reflection = delegate_reflection
761
776
  @klass = delegate_reflection.options[:anonymous_class]
762
777
  @source_reflection_name = delegate_reflection.options[:source]
778
+
779
+ ensure_option_not_given_as_class!(:source_type)
763
780
  end
764
781
 
765
782
  def through_reflection?
@@ -840,8 +857,8 @@ module ActiveRecord
840
857
  source_reflection.scopes + super
841
858
  end
842
859
 
843
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
844
- source_reflection.join_scopes(table, predicate_builder, klass) + super
860
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
861
+ source_reflection.join_scopes(table, predicate_builder, klass, record) + super
845
862
  end
846
863
 
847
864
  def has_scope?
@@ -1013,9 +1030,9 @@ module ActiveRecord
1013
1030
  @previous_reflection = previous_reflection
1014
1031
  end
1015
1032
 
1016
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
1017
- scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1018
- scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
1033
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
1034
+ scopes = @previous_reflection.join_scopes(table, predicate_builder, klass, record) + super
1035
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
1019
1036
  end
1020
1037
 
1021
1038
  def constraints
@@ -5,13 +5,27 @@ module ActiveRecord
5
5
  class BatchEnumerator
6
6
  include Enumerable
7
7
 
8
- def initialize(of: 1000, start: nil, finish: nil, relation:) #:nodoc:
8
+ def initialize(of: 1000, start: nil, finish: nil, relation:) # :nodoc:
9
9
  @of = of
10
10
  @relation = relation
11
11
  @start = start
12
12
  @finish = finish
13
13
  end
14
14
 
15
+ # The primary key value from which the BatchEnumerator starts, inclusive of the value.
16
+ attr_reader :start
17
+
18
+ # The primary key value at which the BatchEnumerator ends, inclusive of the value.
19
+ attr_reader :finish
20
+
21
+ # The relation from which the BatchEnumerator yields batches.
22
+ attr_reader :relation
23
+
24
+ # The size of the batches yielded by the BatchEnumerator.
25
+ def batch_size
26
+ @of
27
+ end
28
+
15
29
  # Looping through a collection of records from the database (using the
16
30
  # +all+ method, for example) is very inefficient since it will try to
17
31
  # instantiate all the objects at once.
@@ -33,11 +47,11 @@ module ActiveRecord
33
47
  # Person.in_batches.each_record.with_index do |person, index|
34
48
  # person.award_trophy(index + 1)
35
49
  # end
36
- def each_record
50
+ def each_record(&block)
37
51
  return to_enum(:each_record) unless block_given?
38
52
 
39
53
  @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true).each do |relation|
40
- relation.records.each { |record| yield record }
54
+ relation.records.each(&block)
41
55
  end
42
56
  end
43
57
 
@@ -75,9 +89,9 @@ module ActiveRecord
75
89
  # Person.in_batches.each do |relation|
76
90
  # relation.update_all(awesome: true)
77
91
  # end
78
- def each
92
+ def each(&block)
79
93
  enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false)
80
- return enum.each { |relation| yield relation } if block_given?
94
+ return enum.each(&block) if block_given?
81
95
  enum
82
96
  end
83
97
  end
@@ -65,10 +65,10 @@ module ActiveRecord
65
65
  #
66
66
  # NOTE: By its nature, batch processing is subject to race conditions if
67
67
  # other processes are modifying the database.
68
- def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
68
+ def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block)
69
69
  if block_given?
70
70
  find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do |records|
71
- records.each { |record| yield record }
71
+ records.each(&block)
72
72
  end
73
73
  else
74
74
  enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
@@ -284,7 +284,7 @@ module ActiveRecord
284
284
  end
285
285
 
286
286
  def act_on_ignored_order(error_on_ignore)
287
- raise_error = (error_on_ignore.nil? ? klass.error_on_ignored_order : error_on_ignore)
287
+ raise_error = (error_on_ignore.nil? ? ActiveRecord.error_on_ignored_order : error_on_ignore)
288
288
 
289
289
  if raise_error
290
290
  raise ArgumentError.new(ORDER_IGNORE_MESSAGE)
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  #
32
32
  # Article.group(:status, :category).count
33
33
  # # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
34
- # ["published", "business"]=>0, ["published", "technology"]=>2}
34
+ # # ["published", "business"]=>0, ["published", "technology"]=>2}
35
35
  #
36
36
  # If #count is used with {Relation#select}[rdoc-ref:QueryMethods#select], it will count the selected columns:
37
37
  #
@@ -83,15 +83,24 @@ module ActiveRecord
83
83
  # #calculate for examples with options.
84
84
  #
85
85
  # Person.sum(:age) # => 4562
86
- def sum(column_name = nil)
86
+ def sum(identity_or_column = nil, &block)
87
87
  if block_given?
88
- unless column_name.nil?
89
- raise ArgumentError, "Column name argument is not supported when a block is passed."
88
+ values = map(&block)
89
+ if identity_or_column.nil? && (values.first.is_a?(Numeric) || values.first(1) == [])
90
+ identity_or_column = 0
90
91
  end
91
92
 
92
- super()
93
+ if identity_or_column.nil?
94
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
95
+ Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4.
96
+ Sum of non-numeric elements requires an initial argument.
97
+ MSG
98
+ values.inject(:+) || 0
99
+ else
100
+ values.sum(identity_or_column)
101
+ end
93
102
  else
94
- calculate(:sum, column_name)
103
+ calculate(:sum, identity_or_column)
95
104
  end
96
105
  end
97
106
 
@@ -146,7 +155,7 @@ module ActiveRecord
146
155
  end
147
156
 
148
157
  # Use #pluck as a shortcut to select one or more attributes without
149
- # loading a bunch of records just to grab the attributes you want.
158
+ # loading an entire record object per row.
150
159
  #
151
160
  # Person.pluck(:name)
152
161
  #
@@ -195,9 +204,9 @@ module ActiveRecord
195
204
  relation.select_values = columns
196
205
  result = skip_query_cache_if_necessary do
197
206
  if where_clause.contradiction?
198
- ActiveRecord::Result.new([], [])
207
+ ActiveRecord::Result.empty
199
208
  else
200
- klass.connection.select_all(relation.arel, nil)
209
+ klass.connection.select_all(relation.arel, "#{klass.name} Pluck")
201
210
  end
202
211
  end
203
212
  type_cast_pluck_values(result, columns)
@@ -286,7 +295,7 @@ module ActiveRecord
286
295
  operation == "count" ? column.count(distinct) : column.public_send(operation)
287
296
  end
288
297
 
289
- def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
298
+ def execute_simple_calculation(operation, column_name, distinct) # :nodoc:
290
299
  if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
291
300
  # Shortcut when limit is zero.
292
301
  return 0 if limit_value == 0
@@ -305,29 +314,21 @@ module ActiveRecord
305
314
  query_builder = relation.arel
306
315
  end
307
316
 
308
- result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
317
+ result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, "#{@klass.name} #{operation.capitalize}") }
309
318
 
310
- type_cast_calculated_value(result.cast_values.first, operation) do |value|
319
+ if operation != "count"
311
320
  type = column.try(:type_caster) ||
312
321
  lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
313
322
  type = type.subtype if Enum::EnumType === type
314
- type.deserialize(value)
315
323
  end
324
+
325
+ type_cast_calculated_value(result.cast_values.first, operation, type)
316
326
  end
317
327
 
318
- def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
328
+ def execute_grouped_calculation(operation, column_name, distinct) # :nodoc:
319
329
  group_fields = group_values
320
330
  group_fields = group_fields.uniq if group_fields.size > 1
321
331
 
322
- unless group_fields == group_values
323
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
324
- `#{operation}` with group by duplicated fields does no longer affect to result in Rails 6.2.
325
- To migrate to Rails 6.2's behavior, use `uniq!(:group)` to deduplicate group fields
326
- (`#{klass.name&.tableize || klass.table_name}.uniq!(:group).#{operation}(#{column_name.inspect})`).
327
- MSG
328
- group_fields = group_values
329
- end
330
-
331
332
  if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
332
333
  association = klass._reflect_on_association(group_fields.first)
333
334
  associated = association && association.belongs_to? # only count belongs_to associations
@@ -344,12 +345,13 @@ module ActiveRecord
344
345
  column = aggregate_column(column_name)
345
346
  column_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
346
347
  select_value = operation_over_aggregate_column(column, operation, distinct)
347
- select_value.as(column_alias)
348
+ select_value.as(connection.quote_column_name(column_alias))
348
349
 
349
350
  select_values = [select_value]
350
351
  select_values += self.select_values unless having_clause.empty?
351
352
 
352
353
  select_values.concat group_columns.map { |aliaz, field|
354
+ aliaz = connection.quote_column_name(aliaz)
353
355
  if field.respond_to?(:as)
354
356
  field.as(aliaz)
355
357
  else
@@ -361,7 +363,7 @@ module ActiveRecord
361
363
  relation.group_values = group_fields
362
364
  relation.select_values = select_values
363
365
 
364
- calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
366
+ calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "#{@klass.name} #{operation.capitalize}") }
365
367
 
366
368
  if association
367
369
  key_ids = calculated_data.collect { |row| row[group_aliases.first] }
@@ -381,20 +383,18 @@ module ActiveRecord
381
383
  end
382
384
  end
383
385
 
384
- type = nil
386
+ if operation != "count"
387
+ type = column.try(:type_caster) ||
388
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
389
+ type = type.subtype if Enum::EnumType === type
390
+ end
391
+
385
392
  hash_rows.each_with_object({}) do |row, result|
386
393
  key = group_aliases.map { |aliaz| row[aliaz] }
387
394
  key = key.first if key.size == 1
388
395
  key = key_records[key] if associated
389
396
 
390
- result[key] = type_cast_calculated_value(row[column_alias], operation) do |value|
391
- unless type
392
- type = column.try(:type_caster) ||
393
- lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
394
- type = type.subtype if Enum::EnumType === type
395
- end
396
- type.deserialize(value)
397
- end
397
+ result[key] = type_cast_calculated_value(row[column_alias], operation, type)
398
398
  end
399
399
  end
400
400
 
@@ -445,16 +445,21 @@ module ActiveRecord
445
445
  result.cast_values(cast_types)
446
446
  end
447
447
 
448
- def type_cast_calculated_value(value, operation)
448
+ def type_cast_calculated_value(value, operation, type)
449
449
  case operation
450
450
  when "count"
451
451
  value.to_i
452
452
  when "sum"
453
- yield value || 0
453
+ type.deserialize(value || 0)
454
454
  when "average"
455
- value&.respond_to?(:to_d) ? value.to_d : value
455
+ case type.type
456
+ when :integer, :decimal
457
+ value&.to_d
458
+ else
459
+ type.deserialize(value)
460
+ end
456
461
  else # "minimum", "maximum"
457
- yield value
462
+ type.deserialize(value)
458
463
  end
459
464
  end
460
465
 
@@ -15,7 +15,8 @@ module ActiveRecord
15
15
  [
16
16
  ActiveRecord::Relation,
17
17
  ActiveRecord::Associations::CollectionProxy,
18
- ActiveRecord::AssociationRelation
18
+ ActiveRecord::AssociationRelation,
19
+ ActiveRecord::DisableJoinsAssociationRelation
19
20
  ].each do |klass|
20
21
  delegate = Class.new(klass) {
21
22
  include ClassSpecificRelation
@@ -61,17 +62,16 @@ module ActiveRecord
61
62
  return if method_defined?(method)
62
63
 
63
64
  if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !DELEGATION_RESERVED_METHOD_NAMES.include?(method.to_s)
64
- definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
65
65
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
66
- def #{method}(#{definition})
67
- scoping { klass.#{method}(#{definition}) }
66
+ def #{method}(...)
67
+ scoping { klass.#{method}(...) }
68
68
  end
69
69
  RUBY
70
70
  else
71
71
  define_method(method) do |*args, &block|
72
72
  scoping { klass.public_send(method, *args, &block) }
73
73
  end
74
- ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
74
+ ruby2_keywords(method)
75
75
  end
76
76
  end
77
77
  end
@@ -87,7 +87,7 @@ module ActiveRecord
87
87
 
88
88
  delegate :to_xml, :encode_with, :length, :each, :join,
89
89
  :[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
90
- :to_sentence, :to_formatted_s, :as_json,
90
+ :to_sentence, :to_fs, :to_formatted_s, :as_json,
91
91
  :shuffle, :split, :slice, :index, :rindex, to: :records
92
92
 
93
93
  delegate :primary_key, :connection, to: :klass
@@ -110,7 +110,7 @@ module ActiveRecord
110
110
  super
111
111
  end
112
112
  end
113
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
113
+ ruby2_keywords(:method_missing)
114
114
  end
115
115
 
116
116
  module ClassMethods # :nodoc: