activerecord 6.1.7 → 7.1.5

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 (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -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 +51 -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 +39 -35
  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/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. 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
@@ -167,6 +166,7 @@ Active Record is an implementation of the object-relational mapping (ORM)
167
166
  pattern[https://www.martinfowler.com/eaaCatalog/activeRecord.html] by the same
168
167
  name described by Martin Fowler:
169
168
 
169
+ >>>
170
170
  "An object that wraps a row in a database table or view,
171
171
  encapsulates the database access, and adds domain logic on that data."
172
172
 
@@ -192,7 +192,7 @@ The latest version of Active Record can be installed with RubyGems:
192
192
 
193
193
  $ gem install activerecord
194
194
 
195
- Source code can be downloaded as part of the Rails project on GitHub:
195
+ Source code can be downloaded as part of the \Rails project on GitHub:
196
196
 
197
197
  * https://github.com/rails/rails/tree/main/activerecord
198
198
 
@@ -210,7 +210,7 @@ API documentation is at:
210
210
 
211
211
  * https://api.rubyonrails.org
212
212
 
213
- Bug reports for the Ruby on Rails project can be filed here:
213
+ Bug reports for the Ruby on \Rails project can be filed here:
214
214
 
215
215
  * https://github.com/rails/rails/issues
216
216
 
@@ -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,9 @@ 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_accessor :owner
37
+ attr_reader :target, :reflection, :disable_joins
37
38
 
38
39
  delegate :options, to: :reflection
39
40
 
@@ -41,9 +42,12 @@ module ActiveRecord
41
42
  reflection.check_validity!
42
43
 
43
44
  @owner, @reflection = owner, reflection
45
+ @disable_joins = @reflection.options[:disable_joins] || false
44
46
 
45
47
  reset
46
48
  reset_scope
49
+
50
+ @skip_strict_loading = nil
47
51
  end
48
52
 
49
53
  # Resets the \loaded flag to +false+ and sets the \target to +nil+.
@@ -51,7 +55,6 @@ module ActiveRecord
51
55
  @loaded = false
52
56
  @target = nil
53
57
  @stale_state = nil
54
- @inversed = false
55
58
  end
56
59
 
57
60
  def reset_negative_cache # :nodoc:
@@ -77,7 +80,6 @@ module ActiveRecord
77
80
  def loaded!
78
81
  @loaded = true
79
82
  @stale_state = stale_state
80
- @inversed = false
81
83
  end
82
84
 
83
85
  # The target is stale if the target no longer points to the record(s) that the
@@ -87,7 +89,7 @@ module ActiveRecord
87
89
  #
88
90
  # Note that if the target has not been loaded, it is not considered stale.
89
91
  def stale_target?
90
- !@inversed && loaded? && @stale_state != stale_state
92
+ loaded? && @stale_state != stale_state
91
93
  end
92
94
 
93
95
  # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -97,8 +99,12 @@ module ActiveRecord
97
99
  end
98
100
 
99
101
  def scope
100
- if (scope = klass.current_scope) && scope.try(:proxy_association) == self
102
+ if disable_joins
103
+ DisableJoinsAssociationScope.create.scope(self)
104
+ elsif (scope = klass.current_scope) && scope.try(:proxy_association) == self
101
105
  scope.spawn
106
+ elsif scope = klass.global_current_scope
107
+ target_scope.merge!(association_scope).merge!(scope)
102
108
  else
103
109
  target_scope.merge!(association_scope)
104
110
  end
@@ -132,15 +138,11 @@ module ActiveRecord
132
138
 
133
139
  def inversed_from(record)
134
140
  self.target = record
135
- @inversed = !!record
136
141
  end
137
142
 
138
143
  def inversed_from_queries(record)
139
144
  if inversable?(record)
140
145
  self.target = record
141
- @inversed = true
142
- else
143
- @inversed = false
144
146
  end
145
147
  end
146
148
 
@@ -191,7 +193,7 @@ module ActiveRecord
191
193
  @reflection = @owner.class._reflect_on_association(reflection_name)
192
194
  end
193
195
 
194
- def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
196
+ def initialize_attributes(record, except_from_scope_attributes = nil) # :nodoc:
195
197
  except_from_scope_attributes ||= {}
196
198
  skip_assign = [reflection.foreign_key, reflection.type].compact
197
199
  assigned_keys = record.changed_attribute_names_to_save
@@ -210,8 +212,14 @@ module ActiveRecord
210
212
  end
211
213
 
212
214
  private
215
+ # Reader and writer methods call this so that consistent errors are presented
216
+ # when the association target class does not exist.
217
+ def ensure_klass_exists!
218
+ klass
219
+ end
220
+
213
221
  def find_target
214
- if strict_loading? && owner.validation_context.nil?
222
+ if violates_strict_loading?
215
223
  Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
216
224
  end
217
225
 
@@ -224,13 +232,32 @@ module ActiveRecord
224
232
  end
225
233
 
226
234
  binds = AssociationScope.get_bind_values(owner, reflection.chain)
227
- sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
235
+ sc.execute(binds, klass.connection) do |record|
236
+ set_inverse_instance(record)
237
+ if owner.strict_loading_n_plus_one_only? && reflection.macro == :has_many
238
+ record.strict_loading!
239
+ else
240
+ record.strict_loading!(false, mode: owner.strict_loading_mode)
241
+ end
242
+ end
228
243
  end
229
244
 
230
- def strict_loading?
245
+ def skip_strict_loading(&block)
246
+ skip_strict_loading_was = @skip_strict_loading
247
+ @skip_strict_loading = true
248
+ yield
249
+ ensure
250
+ @skip_strict_loading = skip_strict_loading_was
251
+ end
252
+
253
+ def violates_strict_loading?
254
+ return if @skip_strict_loading
255
+
256
+ return unless owner.validation_context.nil?
257
+
231
258
  return reflection.strict_loading? if reflection.options.key?(:strict_loading)
232
259
 
233
- owner.strict_loading?
260
+ owner.strict_loading? && !owner.strict_loading_n_plus_one_only?
234
261
  end
235
262
 
236
263
  # The scope for this association.
@@ -241,7 +268,11 @@ module ActiveRecord
241
268
  # actually gets built.
242
269
  def association_scope
243
270
  if klass
244
- @association_scope ||= AssociationScope.scope(self)
271
+ @association_scope ||= if disable_joins
272
+ DisableJoinsAssociationScope.scope(self)
273
+ else
274
+ AssociationScope.scope(self)
275
+ end
245
276
  end
246
277
  end
247
278
 
@@ -273,7 +304,7 @@ module ActiveRecord
273
304
 
274
305
  # Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
275
306
  # 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.
307
+ # a safety check when you are about to assign an associated record.
277
308
  def raise_on_type_mismatch!(record)
278
309
  unless record.is_a?(reflection.klass)
279
310
  fresh_class = reflection.class_name.safe_constantize
@@ -306,7 +337,8 @@ module ActiveRecord
306
337
 
307
338
  # Returns true if record contains the foreign_key
308
339
  def foreign_key_for?(record)
309
- record._has_attribute?(reflection.foreign_key)
340
+ foreign_key = Array(reflection.foreign_key)
341
+ foreign_key.all? { |key| record._has_attribute?(key) }
310
342
  end
311
343
 
312
344
  # 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
16
+ id = reflection.foreign_key.map { |col| owner.public_send(col) }
17
+ else
18
+ primary_key_column = reflection.active_record_primary_key
19
+ id = owner.public_send(reflection.foreign_key)
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