activerecord 6.1.7 → 7.1.0

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 (307) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1516 -1019
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +17 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +50 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +35 -31
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency.rb +26 -16
  27. data/lib/active_record/associations/preloader/association.rb +207 -52
  28. data/lib/active_record/associations/preloader/batch.rb +48 -0
  29. data/lib/active_record/associations/preloader/branch.rb +147 -0
  30. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  31. data/lib/active_record/associations/preloader.rb +50 -121
  32. data/lib/active_record/associations/singular_association.rb +9 -3
  33. data/lib/active_record/associations/through_association.rb +25 -14
  34. data/lib/active_record/associations.rb +423 -289
  35. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  36. data/lib/active_record/attribute_assignment.rb +1 -3
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +61 -14
  39. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  40. data/lib/active_record/attribute_methods/query.rb +31 -19
  41. data/lib/active_record/attribute_methods/read.rb +25 -10
  42. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  44. data/lib/active_record/attribute_methods/write.rb +10 -13
  45. data/lib/active_record/attribute_methods.rb +121 -40
  46. data/lib/active_record/attributes.rb +27 -38
  47. data/lib/active_record/autosave_association.rb +61 -30
  48. data/lib/active_record/base.rb +25 -2
  49. data/lib/active_record/callbacks.rb +18 -34
  50. data/lib/active_record/coders/column_serializer.rb +61 -0
  51. data/lib/active_record/coders/json.rb +1 -1
  52. data/lib/active_record/coders/yaml_column.rb +70 -46
  53. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  54. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -51
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -136
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +622 -149
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
  69. data/lib/active_record/connection_adapters/column.rb +13 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +18 -1
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -52
  83. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +381 -69
  98. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  99. data/lib/active_record/connection_adapters/postgresql_adapter.rb +492 -230
  100. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  101. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  102. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +65 -53
  103. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  104. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
  107. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  108. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
  109. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  110. data/lib/active_record/connection_adapters.rb +9 -6
  111. data/lib/active_record/connection_handling.rb +107 -136
  112. data/lib/active_record/core.rb +194 -224
  113. data/lib/active_record/counter_cache.rb +46 -25
  114. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  115. data/lib/active_record/database_configurations/database_config.rb +21 -12
  116. data/lib/active_record/database_configurations/hash_config.rb +84 -16
  117. data/lib/active_record/database_configurations/url_config.rb +18 -12
  118. data/lib/active_record/database_configurations.rb +95 -59
  119. data/lib/active_record/delegated_type.rb +61 -15
  120. data/lib/active_record/deprecator.rb +7 -0
  121. data/lib/active_record/destroy_association_async_job.rb +3 -1
  122. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  123. data/lib/active_record/dynamic_matchers.rb +1 -1
  124. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  125. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  126. data/lib/active_record/encryption/cipher.rb +53 -0
  127. data/lib/active_record/encryption/config.rb +68 -0
  128. data/lib/active_record/encryption/configurable.rb +60 -0
  129. data/lib/active_record/encryption/context.rb +42 -0
  130. data/lib/active_record/encryption/contexts.rb +76 -0
  131. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  132. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  133. data/lib/active_record/encryption/encryptable_record.rb +224 -0
  134. data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
  135. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  136. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  137. data/lib/active_record/encryption/encryptor.rb +155 -0
  138. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  139. data/lib/active_record/encryption/errors.rb +15 -0
  140. data/lib/active_record/encryption/extended_deterministic_queries.rb +172 -0
  141. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  142. data/lib/active_record/encryption/key.rb +28 -0
  143. data/lib/active_record/encryption/key_generator.rb +53 -0
  144. data/lib/active_record/encryption/key_provider.rb +46 -0
  145. data/lib/active_record/encryption/message.rb +33 -0
  146. data/lib/active_record/encryption/message_serializer.rb +92 -0
  147. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  148. data/lib/active_record/encryption/properties.rb +76 -0
  149. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  150. data/lib/active_record/encryption/scheme.rb +96 -0
  151. data/lib/active_record/encryption.rb +56 -0
  152. data/lib/active_record/enum.rb +156 -62
  153. data/lib/active_record/errors.rb +171 -15
  154. data/lib/active_record/explain.rb +23 -3
  155. data/lib/active_record/explain_registry.rb +11 -6
  156. data/lib/active_record/explain_subscriber.rb +1 -1
  157. data/lib/active_record/fixture_set/file.rb +15 -1
  158. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  159. data/lib/active_record/fixture_set/render_context.rb +2 -0
  160. data/lib/active_record/fixture_set/table_row.rb +70 -14
  161. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  162. data/lib/active_record/fixtures.rb +131 -86
  163. data/lib/active_record/future_result.rb +164 -0
  164. data/lib/active_record/gem_version.rb +3 -3
  165. data/lib/active_record/inheritance.rb +81 -29
  166. data/lib/active_record/insert_all.rb +133 -20
  167. data/lib/active_record/integration.rb +11 -10
  168. data/lib/active_record/internal_metadata.rb +117 -33
  169. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  170. data/lib/active_record/locking/optimistic.rb +36 -21
  171. data/lib/active_record/locking/pessimistic.rb +15 -6
  172. data/lib/active_record/log_subscriber.rb +52 -19
  173. data/lib/active_record/marshalling.rb +56 -0
  174. data/lib/active_record/message_pack.rb +124 -0
  175. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  176. data/lib/active_record/middleware/database_selector.rb +23 -13
  177. data/lib/active_record/middleware/shard_selector.rb +62 -0
  178. data/lib/active_record/migration/command_recorder.rb +108 -13
  179. data/lib/active_record/migration/compatibility.rb +221 -48
  180. data/lib/active_record/migration/default_strategy.rb +23 -0
  181. data/lib/active_record/migration/execution_strategy.rb +19 -0
  182. data/lib/active_record/migration/join_table.rb +1 -1
  183. data/lib/active_record/migration.rb +355 -171
  184. data/lib/active_record/model_schema.rb +116 -97
  185. data/lib/active_record/nested_attributes.rb +36 -15
  186. data/lib/active_record/no_touching.rb +3 -3
  187. data/lib/active_record/normalization.rb +159 -0
  188. data/lib/active_record/persistence.rb +405 -85
  189. data/lib/active_record/promise.rb +84 -0
  190. data/lib/active_record/query_cache.rb +3 -21
  191. data/lib/active_record/query_logs.rb +174 -0
  192. data/lib/active_record/query_logs_formatter.rb +41 -0
  193. data/lib/active_record/querying.rb +29 -6
  194. data/lib/active_record/railtie.rb +219 -43
  195. data/lib/active_record/railties/controller_runtime.rb +13 -9
  196. data/lib/active_record/railties/databases.rake +185 -249
  197. data/lib/active_record/railties/job_runtime.rb +23 -0
  198. data/lib/active_record/readonly_attributes.rb +41 -3
  199. data/lib/active_record/reflection.rb +229 -80
  200. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  201. data/lib/active_record/relation/batches.rb +192 -63
  202. data/lib/active_record/relation/calculations.rb +211 -90
  203. data/lib/active_record/relation/delegation.rb +27 -13
  204. data/lib/active_record/relation/finder_methods.rb +108 -51
  205. data/lib/active_record/relation/merger.rb +22 -13
  206. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  207. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  208. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  209. data/lib/active_record/relation/predicate_builder.rb +27 -20
  210. data/lib/active_record/relation/query_attribute.rb +30 -12
  211. data/lib/active_record/relation/query_methods.rb +654 -127
  212. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  213. data/lib/active_record/relation/spawn_methods.rb +20 -3
  214. data/lib/active_record/relation/where_clause.rb +10 -19
  215. data/lib/active_record/relation.rb +262 -120
  216. data/lib/active_record/result.rb +37 -11
  217. data/lib/active_record/runtime_registry.rb +18 -13
  218. data/lib/active_record/sanitization.rb +65 -20
  219. data/lib/active_record/schema.rb +36 -22
  220. data/lib/active_record/schema_dumper.rb +73 -24
  221. data/lib/active_record/schema_migration.rb +68 -33
  222. data/lib/active_record/scoping/default.rb +72 -15
  223. data/lib/active_record/scoping/named.rb +5 -13
  224. data/lib/active_record/scoping.rb +65 -34
  225. data/lib/active_record/secure_password.rb +60 -0
  226. data/lib/active_record/secure_token.rb +21 -3
  227. data/lib/active_record/serialization.rb +6 -1
  228. data/lib/active_record/signed_id.rb +10 -8
  229. data/lib/active_record/store.rb +10 -10
  230. data/lib/active_record/suppressor.rb +13 -15
  231. data/lib/active_record/table_metadata.rb +16 -3
  232. data/lib/active_record/tasks/database_tasks.rb +225 -136
  233. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  234. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  235. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  236. data/lib/active_record/test_databases.rb +1 -1
  237. data/lib/active_record/test_fixtures.rb +116 -96
  238. data/lib/active_record/timestamp.rb +28 -17
  239. data/lib/active_record/token_for.rb +113 -0
  240. data/lib/active_record/touch_later.rb +11 -6
  241. data/lib/active_record/transactions.rb +48 -27
  242. data/lib/active_record/translation.rb +3 -3
  243. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  244. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  245. data/lib/active_record/type/internal/timezone.rb +7 -2
  246. data/lib/active_record/type/serialized.rb +9 -5
  247. data/lib/active_record/type/time.rb +4 -0
  248. data/lib/active_record/type/type_map.rb +17 -20
  249. data/lib/active_record/type.rb +1 -2
  250. data/lib/active_record/validations/absence.rb +1 -1
  251. data/lib/active_record/validations/associated.rb +4 -4
  252. data/lib/active_record/validations/numericality.rb +5 -4
  253. data/lib/active_record/validations/presence.rb +5 -28
  254. data/lib/active_record/validations/uniqueness.rb +51 -6
  255. data/lib/active_record/validations.rb +8 -4
  256. data/lib/active_record/version.rb +1 -1
  257. data/lib/active_record.rb +335 -32
  258. data/lib/arel/attributes/attribute.rb +0 -8
  259. data/lib/arel/crud.rb +28 -22
  260. data/lib/arel/delete_manager.rb +18 -4
  261. data/lib/arel/errors.rb +10 -0
  262. data/lib/arel/factory_methods.rb +4 -0
  263. data/lib/arel/filter_predications.rb +9 -0
  264. data/lib/arel/insert_manager.rb +2 -3
  265. data/lib/arel/nodes/and.rb +4 -0
  266. data/lib/arel/nodes/binary.rb +6 -1
  267. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  268. data/lib/arel/nodes/casted.rb +1 -1
  269. data/lib/arel/nodes/cte.rb +36 -0
  270. data/lib/arel/nodes/delete_statement.rb +12 -13
  271. data/lib/arel/nodes/filter.rb +10 -0
  272. data/lib/arel/nodes/fragments.rb +35 -0
  273. data/lib/arel/nodes/function.rb +1 -0
  274. data/lib/arel/nodes/homogeneous_in.rb +0 -8
  275. data/lib/arel/nodes/insert_statement.rb +2 -2
  276. data/lib/arel/nodes/leading_join.rb +8 -0
  277. data/lib/arel/nodes/node.rb +111 -2
  278. data/lib/arel/nodes/select_core.rb +2 -2
  279. data/lib/arel/nodes/select_statement.rb +2 -2
  280. data/lib/arel/nodes/sql_literal.rb +6 -0
  281. data/lib/arel/nodes/table_alias.rb +4 -0
  282. data/lib/arel/nodes/update_statement.rb +8 -3
  283. data/lib/arel/nodes.rb +5 -0
  284. data/lib/arel/predications.rb +13 -3
  285. data/lib/arel/select_manager.rb +10 -4
  286. data/lib/arel/table.rb +9 -6
  287. data/lib/arel/tree_manager.rb +0 -12
  288. data/lib/arel/update_manager.rb +18 -4
  289. data/lib/arel/visitors/dot.rb +80 -90
  290. data/lib/arel/visitors/mysql.rb +16 -3
  291. data/lib/arel/visitors/postgresql.rb +0 -10
  292. data/lib/arel/visitors/to_sql.rb +139 -19
  293. data/lib/arel/visitors/visitor.rb +2 -2
  294. data/lib/arel.rb +18 -3
  295. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  296. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  297. data/lib/rails/generators/active_record/migration.rb +3 -1
  298. data/lib/rails/generators/active_record/model/USAGE +113 -0
  299. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  300. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  302. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  303. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  304. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  305. metadata +92 -13
  306. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  307. data/lib/active_record/null_relation.rb +0 -67
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2022 David Heinemeier Hansson
1
+ Copyright (c) David Heinemeier Hansson
2
2
 
3
3
  Arel originally copyright (c) 2007-2016 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
4
4
 
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = Active Record -- Object-relational mapping in Rails
1
+ = Active Record -- Object-relational mapping in \Rails
2
2
 
3
3
  Active Record connects classes to relational database tables to establish an
4
4
  almost zero-configuration persistence layer for applications. The library
@@ -13,29 +13,28 @@ columns. Although these mappings can be defined explicitly, it's recommended
13
13
  to follow naming conventions, especially when getting started with the
14
14
  library.
15
15
 
16
- You can read more about Active Record in the {Active Record Basics}[https://edgeguides.rubyonrails.org/active_record_basics.html] guide.
16
+ You can read more about Active Record in the {Active Record Basics}[https://guides.rubyonrails.org/active_record_basics.html] guide.
17
17
 
18
18
  A short rundown of some of the major features:
19
19
 
20
20
  * Automated mapping between classes and tables, attributes and columns.
21
21
 
22
- class Product < ActiveRecord::Base
23
- end
24
-
25
- {Learn more}[link:classes/ActiveRecord/Base.html]
22
+ class Product < ActiveRecord::Base
23
+ end
26
24
 
27
- The Product class is automatically mapped to the table named "products",
28
- which might look like this:
25
+ The Product class is automatically mapped to the table named "products",
26
+ which might look like this:
29
27
 
30
- CREATE TABLE products (
31
- id bigint NOT NULL auto_increment,
32
- name varchar(255),
33
- PRIMARY KEY (id)
34
- );
28
+ CREATE TABLE products (
29
+ id bigint NOT NULL auto_increment,
30
+ name varchar(255),
31
+ PRIMARY KEY (id)
32
+ );
35
33
 
36
- This would also define the following accessors: <tt>Product#name</tt> and
37
- <tt>Product#name=(new_name)</tt>.
34
+ This would also define the following accessors: <tt>Product#name</tt> and
35
+ <tt>Product#name=(new_name)</tt>.
38
36
 
37
+ {Learn more}[link:classes/ActiveRecord/Base.html]
39
38
 
40
39
  * Associations between objects defined by simple class methods.
41
40
 
@@ -140,7 +139,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
140
139
 
141
140
  * Database agnostic schema management with Migrations.
142
141
 
143
- class AddSystemSettings < ActiveRecord::Migration[6.0]
142
+ class AddSystemSettings < ActiveRecord::Migration[7.1]
144
143
  def up
145
144
  create_table :system_settings do |t|
146
145
  t.string :name
@@ -192,7 +191,7 @@ The latest version of Active Record can be installed with RubyGems:
192
191
 
193
192
  $ gem install activerecord
194
193
 
195
- Source code can be downloaded as part of the Rails project on GitHub:
194
+ Source code can be downloaded as part of the \Rails project on GitHub:
196
195
 
197
196
  * https://github.com/rails/rails/tree/main/activerecord
198
197
 
@@ -210,7 +209,7 @@ API documentation is at:
210
209
 
211
210
  * https://api.rubyonrails.org
212
211
 
213
- Bug reports for the Ruby on Rails project can be filed here:
212
+ Bug reports for the Ruby on \Rails project can be filed here:
214
213
 
215
214
  * https://github.com/rails/rails/issues
216
215
 
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  # See ActiveRecord::Aggregations::ClassMethods for documentation
5
5
  module Aggregations
6
6
  def initialize_dup(*) # :nodoc:
7
- @aggregation_cache = {}
7
+ @aggregation_cache = @aggregation_cache.dup
8
8
  super
9
9
  end
10
10
 
@@ -19,10 +19,12 @@ module ActiveRecord
19
19
  end
20
20
 
21
21
  def init_internals
22
- @aggregation_cache = {}
23
22
  super
23
+ @aggregation_cache = {}
24
24
  end
25
25
 
26
+ # = Active Record \Aggregations
27
+ #
26
28
  # Active Record implements aggregation through a macro-like class method called #composed_of
27
29
  # for representing attributes as value objects. It expresses relationships like "Account [is]
28
30
  # composed of Money [among other things]" or "Person [is] composed of [an] address". Each call
@@ -32,8 +34,8 @@ module ActiveRecord
32
34
  # the database).
33
35
  #
34
36
  # class Customer < ActiveRecord::Base
35
- # composed_of :balance, class_name: "Money", mapping: %w(balance amount)
36
- # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
37
+ # composed_of :balance, class_name: "Money", mapping: { balance: :amount }
38
+ # composed_of :address, mapping: { address_street: :street, address_city: :city }
37
39
  # end
38
40
  #
39
41
  # The customer class now has the following methods to manipulate the value objects:
@@ -150,7 +152,7 @@ module ActiveRecord
150
152
  # class NetworkResource < ActiveRecord::Base
151
153
  # composed_of :cidr,
152
154
  # class_name: 'NetAddr::CIDR',
153
- # mapping: [ %w(network_address network), %w(cidr_range bits) ],
155
+ # mapping: { network_address: :network, cidr_range: :bits },
154
156
  # allow_nil: true,
155
157
  # constructor: Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
156
158
  # converter: Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
@@ -188,10 +190,10 @@ module ActiveRecord
188
190
  # to the Address class, but if the real class name is +CompanyAddress+, you'll have to specify it
189
191
  # with this option.
190
192
  # * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value
191
- # object. Each mapping is represented as an array where the first item is the name of the
192
- # entity attribute and the second item is the name of the attribute in the value object. The
193
+ # object. Each mapping is represented as a key-value pair where the key is the name of the
194
+ # entity attribute and the value is the name of the attribute in the value object. The
193
195
  # order in which mappings are defined determines the order in which attributes are sent to the
194
- # value class constructor.
196
+ # value class constructor. The mapping can be written as a hash or as an array of pairs.
195
197
  # * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped
196
198
  # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all
197
199
  # mapped attributes.
@@ -208,14 +210,15 @@ module ActiveRecord
208
210
  # can return +nil+ to skip the assignment.
209
211
  #
210
212
  # Option examples:
211
- # composed_of :temperature, mapping: %w(reading celsius)
212
- # composed_of :balance, class_name: "Money", mapping: %w(balance amount)
213
+ # composed_of :temperature, mapping: { reading: :celsius }
214
+ # composed_of :balance, class_name: "Money", mapping: { balance: :amount }
215
+ # composed_of :address, mapping: { address_street: :street, address_city: :city }
213
216
  # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
214
217
  # composed_of :gps_location
215
218
  # composed_of :gps_location, allow_nil: true
216
219
  # composed_of :ip_address,
217
220
  # class_name: 'IPAddr',
218
- # mapping: %w(ip to_i),
221
+ # mapping: { ip: :to_i },
219
222
  # constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
220
223
  # converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
221
224
  #
@@ -249,7 +252,7 @@ module ActiveRecord
249
252
  object = constructor.respond_to?(:call) ?
250
253
  constructor.call(*attrs) :
251
254
  class_name.constantize.send(constructor, *attrs)
252
- @aggregation_cache[name] = object
255
+ @aggregation_cache[name] = object.freeze
253
256
  end
254
257
  @aggregation_cache[name]
255
258
  end
@@ -264,7 +267,7 @@ module ActiveRecord
264
267
  end
265
268
 
266
269
  hash_from_multiparameter_assignment = part.is_a?(Hash) &&
267
- part.each_key.all? { |k| k.is_a?(Integer) }
270
+ part.keys.all?(Integer)
268
271
  if hash_from_multiparameter_assignment
269
272
  raise ArgumentError unless part.size == part.each_key.max
270
273
  part = klass.new(*part.sort.map(&:last))
@@ -275,7 +278,7 @@ module ActiveRecord
275
278
  @aggregation_cache[name] = nil
276
279
  else
277
280
  mapping.each { |key, value| write_attribute(key, part.send(value)) }
278
- @aggregation_cache[name] = part.freeze
281
+ @aggregation_cache[name] = part.dup.freeze
279
282
  end
280
283
  end
281
284
  end
@@ -16,7 +16,7 @@ module ActiveRecord
16
16
  end
17
17
 
18
18
  %w(insert insert_all insert! insert_all! upsert upsert_all).each do |method|
19
- class_eval <<~RUBY
19
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
20
20
  def #{method}(attributes, **kwargs)
21
21
  if @association.reflection.through_reflection?
22
22
  raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
@@ -27,16 +27,6 @@ module ActiveRecord
27
27
  RUBY
28
28
  end
29
29
 
30
- def build(attributes = nil, &block)
31
- if attributes.is_a?(Array)
32
- attributes.collect { |attr| build(attr, &block) }
33
- else
34
- block = current_scope_restoring_block(&block)
35
- scoping { _new(attributes, &block) }
36
- end
37
- end
38
- alias new build
39
-
40
30
  private
41
31
  def _new(attributes, &block)
42
32
  @association.build(attributes, &block)
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
  # Associations in Active Record are middlemen between the object that
20
20
  # holds the association, known as the <tt>owner</tt>, and the associated
21
21
  # result set, known as the <tt>target</tt>. Association metadata is available in
22
- # <tt>reflection</tt>, which is an instance of <tt>ActiveRecord::Reflection::AssociationReflection</tt>.
22
+ # <tt>reflection</tt>, which is an instance of +ActiveRecord::Reflection::AssociationReflection+.
23
23
  #
24
24
  # For example, given
25
25
  #
@@ -32,8 +32,8 @@ module ActiveRecord
32
32
  # The association of <tt>blog.posts</tt> has the object +blog+ as its
33
33
  # <tt>owner</tt>, the collection of its posts as <tt>target</tt>, and
34
34
  # the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
35
- class Association #:nodoc:
36
- attr_reader :owner, :target, :reflection
35
+ class Association # :nodoc:
36
+ attr_reader :owner, :target, :reflection, :disable_joins
37
37
 
38
38
  delegate :options, to: :reflection
39
39
 
@@ -41,9 +41,12 @@ module ActiveRecord
41
41
  reflection.check_validity!
42
42
 
43
43
  @owner, @reflection = owner, reflection
44
+ @disable_joins = @reflection.options[:disable_joins] || false
44
45
 
45
46
  reset
46
47
  reset_scope
48
+
49
+ @skip_strict_loading = nil
47
50
  end
48
51
 
49
52
  # Resets the \loaded flag to +false+ and sets the \target to +nil+.
@@ -51,7 +54,6 @@ module ActiveRecord
51
54
  @loaded = false
52
55
  @target = nil
53
56
  @stale_state = nil
54
- @inversed = false
55
57
  end
56
58
 
57
59
  def reset_negative_cache # :nodoc:
@@ -77,7 +79,6 @@ module ActiveRecord
77
79
  def loaded!
78
80
  @loaded = true
79
81
  @stale_state = stale_state
80
- @inversed = false
81
82
  end
82
83
 
83
84
  # The target is stale if the target no longer points to the record(s) that the
@@ -87,7 +88,7 @@ module ActiveRecord
87
88
  #
88
89
  # Note that if the target has not been loaded, it is not considered stale.
89
90
  def stale_target?
90
- !@inversed && loaded? && @stale_state != stale_state
91
+ loaded? && @stale_state != stale_state
91
92
  end
92
93
 
93
94
  # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -97,8 +98,12 @@ module ActiveRecord
97
98
  end
98
99
 
99
100
  def scope
100
- if (scope = klass.current_scope) && scope.try(:proxy_association) == self
101
+ if disable_joins
102
+ DisableJoinsAssociationScope.create.scope(self)
103
+ elsif (scope = klass.current_scope) && scope.try(:proxy_association) == self
101
104
  scope.spawn
105
+ elsif scope = klass.global_current_scope
106
+ target_scope.merge!(association_scope).merge!(scope)
102
107
  else
103
108
  target_scope.merge!(association_scope)
104
109
  end
@@ -132,15 +137,11 @@ module ActiveRecord
132
137
 
133
138
  def inversed_from(record)
134
139
  self.target = record
135
- @inversed = !!record
136
140
  end
137
141
 
138
142
  def inversed_from_queries(record)
139
143
  if inversable?(record)
140
144
  self.target = record
141
- @inversed = true
142
- else
143
- @inversed = false
144
145
  end
145
146
  end
146
147
 
@@ -191,7 +192,7 @@ module ActiveRecord
191
192
  @reflection = @owner.class._reflect_on_association(reflection_name)
192
193
  end
193
194
 
194
- def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
195
+ def initialize_attributes(record, except_from_scope_attributes = nil) # :nodoc:
195
196
  except_from_scope_attributes ||= {}
196
197
  skip_assign = [reflection.foreign_key, reflection.type].compact
197
198
  assigned_keys = record.changed_attribute_names_to_save
@@ -210,8 +211,14 @@ module ActiveRecord
210
211
  end
211
212
 
212
213
  private
214
+ # Reader and writer methods call this so that consistent errors are presented
215
+ # when the association target class does not exist.
216
+ def ensure_klass_exists!
217
+ klass
218
+ end
219
+
213
220
  def find_target
214
- if strict_loading? && owner.validation_context.nil?
221
+ if violates_strict_loading?
215
222
  Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
216
223
  end
217
224
 
@@ -224,13 +231,32 @@ module ActiveRecord
224
231
  end
225
232
 
226
233
  binds = AssociationScope.get_bind_values(owner, reflection.chain)
227
- sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
234
+ sc.execute(binds, klass.connection) do |record|
235
+ set_inverse_instance(record)
236
+ if owner.strict_loading_n_plus_one_only? && reflection.macro == :has_many
237
+ record.strict_loading!
238
+ else
239
+ record.strict_loading!(false, mode: owner.strict_loading_mode)
240
+ end
241
+ end
228
242
  end
229
243
 
230
- def strict_loading?
244
+ def skip_strict_loading(&block)
245
+ skip_strict_loading_was = @skip_strict_loading
246
+ @skip_strict_loading = true
247
+ yield
248
+ ensure
249
+ @skip_strict_loading = skip_strict_loading_was
250
+ end
251
+
252
+ def violates_strict_loading?
253
+ return if @skip_strict_loading
254
+
255
+ return unless owner.validation_context.nil?
256
+
231
257
  return reflection.strict_loading? if reflection.options.key?(:strict_loading)
232
258
 
233
- owner.strict_loading?
259
+ owner.strict_loading? && !owner.strict_loading_n_plus_one_only?
234
260
  end
235
261
 
236
262
  # The scope for this association.
@@ -241,7 +267,11 @@ module ActiveRecord
241
267
  # actually gets built.
242
268
  def association_scope
243
269
  if klass
244
- @association_scope ||= AssociationScope.scope(self)
270
+ @association_scope ||= if disable_joins
271
+ DisableJoinsAssociationScope.scope(self)
272
+ else
273
+ AssociationScope.scope(self)
274
+ end
245
275
  end
246
276
  end
247
277
 
@@ -273,7 +303,7 @@ module ActiveRecord
273
303
 
274
304
  # Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
275
305
  # the kind of the class of the associated objects. Meant to be used as
276
- # a sanity check when you are about to assign an associated record.
306
+ # a safety check when you are about to assign an associated record.
277
307
  def raise_on_type_mismatch!(record)
278
308
  unless record.is_a?(reflection.klass)
279
309
  fresh_class = reflection.class_name.safe_constantize
@@ -306,7 +336,8 @@ module ActiveRecord
306
336
 
307
337
  # Returns true if record contains the foreign_key
308
338
  def foreign_key_for?(record)
309
- record._has_attribute?(reflection.foreign_key)
339
+ foreign_key = Array(reflection.foreign_key)
340
+ foreign_key.all? { |key| record._has_attribute?(key) }
310
341
  end
311
342
 
312
343
  # This should be implemented to return the values of the relevant key(s) on the owner,
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Associations
5
- class AssociationScope #:nodoc:
5
+ class AssociationScope # :nodoc:
6
6
  def self.scope(association)
7
7
  INSTANCE.scope(association)
8
8
  end
@@ -35,7 +35,7 @@ module ActiveRecord
35
35
  binds = []
36
36
  last_reflection = chain.last
37
37
 
38
- binds << last_reflection.join_id_for(owner)
38
+ binds.push(*last_reflection.join_id_for(owner))
39
39
  if last_reflection.type
40
40
  binds << owner.class.polymorphic_name
41
41
  end
@@ -56,12 +56,15 @@ module ActiveRecord
56
56
  end
57
57
 
58
58
  def last_chain_scope(scope, reflection, owner)
59
- primary_key = reflection.join_primary_key
60
- foreign_key = reflection.join_foreign_key
59
+ primary_key = Array(reflection.join_primary_key)
60
+ foreign_key = Array(reflection.join_foreign_key)
61
61
 
62
62
  table = reflection.aliased_table
63
- value = transform_value(owner[foreign_key])
64
- scope = apply_scope(scope, table, primary_key, value)
63
+ primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
64
+ primary_key_foreign_key_pairs.each do |join_key, foreign_key|
65
+ value = transform_value(owner._read_attribute(foreign_key))
66
+ scope = apply_scope(scope, table, join_key, value)
67
+ end
65
68
 
66
69
  if reflection.type
67
70
  polymorphic_type = transform_value(owner.class.polymorphic_name)
@@ -76,19 +79,23 @@ module ActiveRecord
76
79
  end
77
80
 
78
81
  def next_chain_scope(scope, reflection, next_reflection)
79
- primary_key = reflection.join_primary_key
80
- foreign_key = reflection.join_foreign_key
82
+ primary_key = Array(reflection.join_primary_key)
83
+ foreign_key = Array(reflection.join_foreign_key)
81
84
 
82
85
  table = reflection.aliased_table
83
86
  foreign_table = next_reflection.aliased_table
84
- constraint = table[primary_key].eq(foreign_table[foreign_key])
87
+
88
+ primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
89
+ constraints = primary_key_foreign_key_pairs.map do |join_primary_key, foreign_key|
90
+ table[join_primary_key].eq(foreign_table[foreign_key])
91
+ end.inject(&:and)
85
92
 
86
93
  if reflection.type
87
94
  value = transform_value(next_reflection.klass.polymorphic_name)
88
95
  scope = apply_scope(scope, table, reflection.type, value)
89
96
  end
90
97
 
91
- scope.joins!(join(foreign_table, constraint))
98
+ scope.joins!(join(foreign_table, constraints))
92
99
  end
93
100
 
94
101
  class ReflectionProxy < SimpleDelegator # :nodoc:
@@ -123,8 +130,6 @@ module ActiveRecord
123
130
 
124
131
  chain_head = chain.first
125
132
  chain.reverse_each do |reflection|
126
- # Exclude the scope of the association itself, because that
127
- # was already merged in the #scope method.
128
133
  reflection.constraints.each do |scope_chain_item|
129
134
  item = eval_scope(reflection, scope_chain_item, owner)
130
135
 
@@ -3,7 +3,7 @@
3
3
  module ActiveRecord
4
4
  module Associations
5
5
  # = Active Record Belongs To Association
6
- class BelongsToAssociation < SingularAssociation #:nodoc:
6
+ class BelongsToAssociation < SingularAssociation # :nodoc:
7
7
  def handle_dependency
8
8
  return unless load_target
9
9
 
@@ -11,8 +11,13 @@ module ActiveRecord
11
11
  when :destroy
12
12
  raise ActiveRecord::Rollback unless target.destroy
13
13
  when :destroy_async
14
- id = owner.public_send(reflection.foreign_key.to_sym)
15
- primary_key_column = reflection.active_record_primary_key.to_sym
14
+ if reflection.foreign_key.is_a?(Array)
15
+ primary_key_column = reflection.active_record_primary_key.map(&:to_sym)
16
+ id = reflection.foreign_key.map { |col| owner.public_send(col.to_sym) }
17
+ else
18
+ primary_key_column = reflection.active_record_primary_key.to_sym
19
+ id = owner.public_send(reflection.foreign_key.to_sym)
20
+ end
16
21
 
17
22
  enqueue_destroy_association(
18
23
  owner_model_name: owner.class.to_s,
@@ -55,7 +60,8 @@ module ActiveRecord
55
60
 
56
61
  def decrement_counters_before_last_save
57
62
  if reflection.polymorphic?
58
- model_was = owner.attribute_before_last_save(reflection.foreign_type)&.constantize
63
+ model_type_was = owner.attribute_before_last_save(reflection.foreign_type)
64
+ model_was = owner.class.polymorphic_class_for(model_type_was) if model_type_was
59
65
  else
60
66
  model_was = klass
61
67
  end
@@ -68,6 +74,14 @@ module ActiveRecord
68
74
  end
69
75
 
70
76
  def target_changed?
77
+ owner.attribute_changed?(reflection.foreign_key) || (!foreign_key_present? && target&.new_record?)
78
+ end
79
+
80
+ def target_previously_changed?
81
+ owner.attribute_previously_changed?(reflection.foreign_key)
82
+ end
83
+
84
+ def saved_change_to_target?
71
85
  owner.saved_change_to_attribute?(reflection.foreign_key)
72
86
  end
73
87
 
@@ -77,6 +91,8 @@ module ActiveRecord
77
91
  raise_on_type_mismatch!(record)
78
92
  set_inverse_instance(record)
79
93
  @updated = true
94
+ elsif target
95
+ remove_inverse_instance(target)
80
96
  end
81
97
 
82
98
  replace_keys(record, force: true)
@@ -108,10 +124,13 @@ module ActiveRecord
108
124
  end
109
125
 
110
126
  def replace_keys(record, force: false)
111
- target_key = record ? record._read_attribute(primary_key(record.class)) : nil
127
+ target_key_values = record ? Array(primary_key(record.class)).map { |key| record._read_attribute(key) } : []
128
+ reflection_fk = Array(reflection.foreign_key)
112
129
 
113
- if force || owner[reflection.foreign_key] != target_key
114
- owner[reflection.foreign_key] = target_key
130
+ if force || reflection_fk.map { |fk| owner._read_attribute(fk) } != target_key_values
131
+ reflection_fk.zip(target_key_values).each do |key, value|
132
+ owner[key] = value
133
+ end
115
134
  end
116
135
  end
117
136
 
@@ -120,12 +139,12 @@ module ActiveRecord
120
139
  end
121
140
 
122
141
  def foreign_key_present?
123
- owner._read_attribute(reflection.foreign_key)
142
+ Array(reflection.foreign_key).all? { |fk| owner._read_attribute(fk) }
124
143
  end
125
144
 
126
145
  def invertible_for?(record)
127
146
  inverse = inverse_reflection_for(record)
128
- inverse && (inverse.has_one? || ActiveRecord::Base.has_many_inversing)
147
+ inverse && (inverse.has_one? || inverse.klass.has_many_inversing)
129
148
  end
130
149
 
131
150
  def stale_state
@@ -3,13 +3,21 @@
3
3
  module ActiveRecord
4
4
  module Associations
5
5
  # = Active Record Belongs To Polymorphic Association
6
- class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
6
+ class BelongsToPolymorphicAssociation < BelongsToAssociation # :nodoc:
7
7
  def klass
8
8
  type = owner[reflection.foreign_type]
9
9
  type.presence && owner.class.polymorphic_class_for(type)
10
10
  end
11
11
 
12
12
  def target_changed?
13
+ super || owner.attribute_changed?(reflection.foreign_type)
14
+ end
15
+
16
+ def target_previously_changed?
17
+ super || owner.attribute_previously_changed?(reflection.foreign_type)
18
+ end
19
+
20
+ def saved_change_to_target?
13
21
  super || owner.saved_change_to_attribute?(reflection.foreign_type)
14
22
  end
15
23
 
@@ -19,7 +27,7 @@ module ActiveRecord
19
27
 
20
28
  target_type = record ? record.class.polymorphic_name : nil
21
29
 
22
- if force || owner[reflection.foreign_type] != target_type
30
+ if force || owner._read_attribute(reflection.foreign_type) != target_type
23
31
  owner[reflection.foreign_type] = target_type
24
32
  end
25
33
  end
@@ -12,14 +12,14 @@
12
12
  # - HasManyAssociation
13
13
 
14
14
  module ActiveRecord::Associations::Builder # :nodoc:
15
- class Association #:nodoc:
15
+ class Association # :nodoc:
16
16
  class << self
17
17
  attr_accessor :extensions
18
18
  end
19
19
  self.extensions = []
20
20
 
21
21
  VALID_OPTIONS = [
22
- :class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading
22
+ :class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading, :query_constraints
23
23
  ].freeze # :nodoc:
24
24
 
25
25
  def self.build(model, name, scope, options, &block)
@@ -33,6 +33,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
33
33
  define_accessors model, reflection
34
34
  define_callbacks model, reflection
35
35
  define_validations model, reflection
36
+ define_change_tracking_methods model, reflection
36
37
  reflection
37
38
  end
38
39
 
@@ -117,14 +118,18 @@ module ActiveRecord::Associations::Builder # :nodoc:
117
118
  # noop
118
119
  end
119
120
 
121
+ def self.define_change_tracking_methods(model, reflection)
122
+ # noop
123
+ end
124
+
120
125
  def self.valid_dependent_options
121
126
  raise NotImplementedError
122
127
  end
123
128
 
124
129
  def self.check_dependent_options(dependent, model)
125
130
  if dependent == :destroy_async && !model.destroy_association_async_job
126
- err_message = "ActiveJob is required to use destroy_async on associations"
127
- raise ActiveRecord::ActiveJobRequiredError, err_message
131
+ err_message = "A valid destroy_association_async_job is required to use `dependent: :destroy_async` on associations"
132
+ raise ActiveRecord::ConfigurationError, err_message
128
133
  end
129
134
  unless valid_dependent_options.include? dependent
130
135
  raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
@@ -158,6 +163,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
158
163
 
159
164
  private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
160
165
  :define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
161
- :valid_dependent_options, :check_dependent_options, :add_destroy_callbacks, :add_after_commit_jobs_callback
166
+ :define_change_tracking_methods, :valid_dependent_options, :check_dependent_options,
167
+ :add_destroy_callbacks, :add_after_commit_jobs_callback
162
168
  end
163
169
  end