activerecord 7.1.5.2 → 8.1.2.1

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 (244) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +567 -2443
  3. data/README.rdoc +16 -16
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +3 -2
  6. data/lib/active_record/associations/alias_tracker.rb +31 -23
  7. data/lib/active_record/associations/association.rb +43 -12
  8. data/lib/active_record/associations/belongs_to_association.rb +31 -8
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/association.rb +23 -11
  11. data/lib/active_record/associations/builder/belongs_to.rb +18 -4
  12. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  14. data/lib/active_record/associations/builder/has_many.rb +3 -4
  15. data/lib/active_record/associations/builder/has_one.rb +3 -4
  16. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  17. data/lib/active_record/associations/collection_association.rb +17 -9
  18. data/lib/active_record/associations/collection_proxy.rb +36 -5
  19. data/lib/active_record/associations/deprecation.rb +88 -0
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  21. data/lib/active_record/associations/errors.rb +268 -0
  22. data/lib/active_record/associations/has_many_association.rb +1 -1
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  24. data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +4 -2
  26. data/lib/active_record/associations/nested_error.rb +47 -0
  27. data/lib/active_record/associations/preloader/association.rb +4 -3
  28. data/lib/active_record/associations/preloader/batch.rb +7 -1
  29. data/lib/active_record/associations/preloader/branch.rb +8 -1
  30. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  31. data/lib/active_record/associations/singular_association.rb +14 -3
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +250 -315
  34. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  35. data/lib/active_record/attribute_assignment.rb +0 -2
  36. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  37. data/lib/active_record/attribute_methods/primary_key.rb +25 -61
  38. data/lib/active_record/attribute_methods/query.rb +34 -0
  39. data/lib/active_record/attribute_methods/read.rb +1 -13
  40. data/lib/active_record/attribute_methods/serialization.rb +20 -27
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
  42. data/lib/active_record/attribute_methods.rb +71 -75
  43. data/lib/active_record/attributes.rb +96 -68
  44. data/lib/active_record/autosave_association.rb +93 -58
  45. data/lib/active_record/base.rb +5 -7
  46. data/lib/active_record/callbacks.rb +1 -1
  47. data/lib/active_record/coders/json.rb +14 -5
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +136 -34
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
  62. data/lib/active_record/connection_adapters/column.rb +17 -4
  63. data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
  64. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
  65. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -46
  68. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
  70. data/lib/active_record/connection_adapters/pool_config.rb +14 -13
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  74. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  75. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  78. data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
  79. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  80. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  81. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +44 -41
  82. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
  83. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
  84. data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
  85. data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
  86. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  87. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
  88. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
  89. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
  90. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  91. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
  92. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
  93. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
  94. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  95. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
  96. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
  97. data/lib/active_record/connection_adapters.rb +66 -0
  98. data/lib/active_record/connection_handling.rb +88 -46
  99. data/lib/active_record/core.rb +142 -58
  100. data/lib/active_record/counter_cache.rb +52 -18
  101. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
  102. data/lib/active_record/database_configurations/database_config.rb +28 -5
  103. data/lib/active_record/database_configurations/hash_config.rb +103 -41
  104. data/lib/active_record/database_configurations/url_config.rb +30 -1
  105. data/lib/active_record/database_configurations.rb +8 -4
  106. data/lib/active_record/delegated_type.rb +43 -19
  107. data/lib/active_record/dynamic_matchers.rb +56 -71
  108. data/lib/active_record/encryption/config.rb +3 -1
  109. data/lib/active_record/encryption/encryptable_record.rb +12 -12
  110. data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
  111. data/lib/active_record/encryption/encryptor.rb +58 -22
  112. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  113. data/lib/active_record/encryption/key_provider.rb +1 -1
  114. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  115. data/lib/active_record/encryption/message_serializer.rb +4 -0
  116. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  117. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  118. data/lib/active_record/encryption/scheme.rb +9 -2
  119. data/lib/active_record/enum.rb +57 -36
  120. data/lib/active_record/errors.rb +76 -26
  121. data/lib/active_record/explain.rb +14 -25
  122. data/lib/active_record/explain_registry.rb +51 -2
  123. data/lib/active_record/filter_attribute_handler.rb +73 -0
  124. data/lib/active_record/fixture_set/table_row.rb +19 -2
  125. data/lib/active_record/fixtures.rb +39 -35
  126. data/lib/active_record/future_result.rb +21 -13
  127. data/lib/active_record/gem_version.rb +3 -3
  128. data/lib/active_record/inheritance.rb +5 -3
  129. data/lib/active_record/insert_all.rb +28 -20
  130. data/lib/active_record/integration.rb +4 -1
  131. data/lib/active_record/internal_metadata.rb +48 -34
  132. data/lib/active_record/locking/optimistic.rb +15 -7
  133. data/lib/active_record/locking/pessimistic.rb +5 -0
  134. data/lib/active_record/log_subscriber.rb +3 -34
  135. data/lib/active_record/message_pack.rb +1 -1
  136. data/lib/active_record/middleware/shard_selector.rb +34 -17
  137. data/lib/active_record/migration/command_recorder.rb +46 -14
  138. data/lib/active_record/migration/compatibility.rb +40 -25
  139. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  140. data/lib/active_record/migration/default_strategy.rb +4 -5
  141. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  142. data/lib/active_record/migration.rb +119 -103
  143. data/lib/active_record/model_schema.rb +66 -78
  144. data/lib/active_record/nested_attributes.rb +17 -9
  145. data/lib/active_record/persistence.rb +161 -454
  146. data/lib/active_record/query_cache.rb +33 -15
  147. data/lib/active_record/query_logs.rb +106 -39
  148. data/lib/active_record/query_logs_formatter.rb +17 -28
  149. data/lib/active_record/querying.rb +28 -16
  150. data/lib/active_record/railtie.rb +61 -74
  151. data/lib/active_record/railties/controller_runtime.rb +19 -5
  152. data/lib/active_record/railties/databases.rake +64 -78
  153. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  154. data/lib/active_record/railties/job_runtime.rb +10 -11
  155. data/lib/active_record/reflection.rb +147 -53
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  157. data/lib/active_record/relation/batches.rb +153 -73
  158. data/lib/active_record/relation/calculations.rb +146 -96
  159. data/lib/active_record/relation/delegation.rb +30 -23
  160. data/lib/active_record/relation/finder_methods.rb +64 -34
  161. data/lib/active_record/relation/merger.rb +12 -14
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  163. data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  165. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  166. data/lib/active_record/relation/predicate_builder.rb +25 -10
  167. data/lib/active_record/relation/query_attribute.rb +4 -2
  168. data/lib/active_record/relation/query_methods.rb +351 -124
  169. data/lib/active_record/relation/spawn_methods.rb +9 -25
  170. data/lib/active_record/relation/where_clause.rb +17 -30
  171. data/lib/active_record/relation.rb +590 -124
  172. data/lib/active_record/result.rb +131 -59
  173. data/lib/active_record/runtime_registry.rb +44 -21
  174. data/lib/active_record/sanitization.rb +33 -25
  175. data/lib/active_record/schema.rb +8 -6
  176. data/lib/active_record/schema_dumper.rb +66 -31
  177. data/lib/active_record/schema_migration.rb +31 -14
  178. data/lib/active_record/scoping/named.rb +6 -2
  179. data/lib/active_record/scoping.rb +0 -1
  180. data/lib/active_record/secure_token.rb +3 -3
  181. data/lib/active_record/signed_id.rb +68 -20
  182. data/lib/active_record/statement_cache.rb +29 -25
  183. data/lib/active_record/store.rb +51 -22
  184. data/lib/active_record/structured_event_subscriber.rb +85 -0
  185. data/lib/active_record/table_metadata.rb +7 -33
  186. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  187. data/lib/active_record/tasks/database_tasks.rb +118 -90
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +17 -28
  191. data/lib/active_record/test_databases.rb +14 -4
  192. data/lib/active_record/test_fixtures.rb +123 -89
  193. data/lib/active_record/testing/query_assertions.rb +127 -0
  194. data/lib/active_record/timestamp.rb +6 -4
  195. data/lib/active_record/token_for.rb +22 -12
  196. data/lib/active_record/touch_later.rb +1 -1
  197. data/lib/active_record/transaction.rb +129 -0
  198. data/lib/active_record/transactions.rb +97 -18
  199. data/lib/active_record/translation.rb +0 -2
  200. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  201. data/lib/active_record/type/internal/timezone.rb +7 -0
  202. data/lib/active_record/type/json.rb +15 -2
  203. data/lib/active_record/type/serialized.rb +12 -7
  204. data/lib/active_record/type/type_map.rb +1 -1
  205. data/lib/active_record/type_caster/connection.rb +5 -4
  206. data/lib/active_record/validations/associated.rb +10 -4
  207. data/lib/active_record/validations/uniqueness.rb +23 -18
  208. data/lib/active_record/validations.rb +4 -1
  209. data/lib/active_record.rb +203 -59
  210. data/lib/arel/alias_predication.rb +3 -1
  211. data/lib/arel/collectors/bind.rb +4 -2
  212. data/lib/arel/collectors/composite.rb +7 -0
  213. data/lib/arel/collectors/sql_string.rb +2 -2
  214. data/lib/arel/collectors/substitute_binds.rb +3 -3
  215. data/lib/arel/crud.rb +8 -11
  216. data/lib/arel/delete_manager.rb +5 -0
  217. data/lib/arel/nodes/binary.rb +1 -7
  218. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  219. data/lib/arel/nodes/count.rb +2 -2
  220. data/lib/arel/nodes/delete_statement.rb +4 -2
  221. data/lib/arel/nodes/function.rb +4 -10
  222. data/lib/arel/nodes/named_function.rb +2 -2
  223. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  224. data/lib/arel/nodes/node.rb +6 -5
  225. data/lib/arel/nodes/sql_literal.rb +8 -1
  226. data/lib/arel/nodes/update_statement.rb +4 -2
  227. data/lib/arel/nodes.rb +2 -4
  228. data/lib/arel/predications.rb +1 -1
  229. data/lib/arel/select_manager.rb +14 -5
  230. data/lib/arel/table.rb +3 -7
  231. data/lib/arel/tree_manager.rb +3 -2
  232. data/lib/arel/update_manager.rb +7 -1
  233. data/lib/arel/visitors/dot.rb +3 -3
  234. data/lib/arel/visitors/mysql.rb +9 -4
  235. data/lib/arel/visitors/postgresql.rb +56 -12
  236. data/lib/arel/visitors/sqlite.rb +80 -8
  237. data/lib/arel/visitors/to_sql.rb +34 -37
  238. data/lib/arel.rb +10 -4
  239. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  240. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  241. metadata +23 -14
  242. data/lib/active_record/explain_subscriber.rb +0 -34
  243. data/lib/active_record/normalization.rb +0 -167
  244. data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -1,268 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- class AssociationNotFoundError < ConfigurationError # :nodoc:
5
- attr_reader :record, :association_name
6
-
7
- def initialize(record = nil, association_name = nil)
8
- @record = record
9
- @association_name = association_name
10
- if record && association_name
11
- super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
12
- else
13
- super("Association was not found.")
14
- end
15
- end
16
-
17
- if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
18
- include DidYouMean::Correctable
19
-
20
- def corrections
21
- if record && association_name
22
- @corrections ||= begin
23
- maybe_these = record.class.reflections.keys
24
- DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(association_name)
25
- end
26
- else
27
- []
28
- end
29
- end
30
- end
31
- end
32
-
33
- class InverseOfAssociationNotFoundError < ActiveRecordError # :nodoc:
34
- attr_reader :reflection, :associated_class
35
-
36
- def initialize(reflection = nil, associated_class = nil)
37
- if reflection
38
- @reflection = reflection
39
- @associated_class = associated_class.nil? ? reflection.klass : associated_class
40
- super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
41
- else
42
- super("Could not find the inverse association.")
43
- end
44
- end
45
-
46
- if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
47
- include DidYouMean::Correctable
48
-
49
- def corrections
50
- if reflection && associated_class
51
- @corrections ||= begin
52
- maybe_these = associated_class.reflections.keys
53
- DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(reflection.options[:inverse_of].to_s)
54
- end
55
- else
56
- []
57
- end
58
- end
59
- end
60
- end
61
-
62
- class InverseOfAssociationRecursiveError < ActiveRecordError # :nodoc:
63
- attr_reader :reflection
64
- def initialize(reflection = nil)
65
- if reflection
66
- @reflection = reflection
67
- super("Inverse association #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{reflection.class_name}) is recursive.")
68
- else
69
- super("Inverse association is recursive.")
70
- end
71
- end
72
- end
73
-
74
- class HasManyThroughAssociationNotFoundError < ActiveRecordError # :nodoc:
75
- attr_reader :owner_class, :reflection
76
-
77
- def initialize(owner_class = nil, reflection = nil)
78
- if owner_class && reflection
79
- @owner_class = owner_class
80
- @reflection = reflection
81
- super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class.name}")
82
- else
83
- super("Could not find the association.")
84
- end
85
- end
86
-
87
- if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
88
- include DidYouMean::Correctable
89
-
90
- def corrections
91
- if owner_class && reflection
92
- @corrections ||= begin
93
- maybe_these = owner_class.reflections.keys
94
- maybe_these -= [reflection.name.to_s] # remove failing reflection
95
- DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(reflection.options[:through].to_s)
96
- end
97
- else
98
- []
99
- end
100
- end
101
- end
102
- end
103
-
104
- class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError # :nodoc:
105
- def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
106
- if owner_class_name && reflection && source_reflection
107
- super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}' without 'source_type'. Try adding 'source_type: \"#{reflection.name.to_s.classify}\"' to 'has_many :through' definition.")
108
- else
109
- super("Cannot have a has_many :through association.")
110
- end
111
- end
112
- end
113
-
114
- class HasManyThroughAssociationPolymorphicThroughError < ActiveRecordError # :nodoc:
115
- def initialize(owner_class_name = nil, reflection = nil)
116
- if owner_class_name && reflection
117
- super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
118
- else
119
- super("Cannot have a has_many :through association.")
120
- end
121
- end
122
- end
123
-
124
- class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError # :nodoc:
125
- def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
126
- if owner_class_name && reflection && source_reflection
127
- super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
128
- else
129
- super("Cannot have a has_many :through association.")
130
- end
131
- end
132
- end
133
-
134
- class HasOneThroughCantAssociateThroughCollection < ActiveRecordError # :nodoc:
135
- def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
136
- if owner_class_name && reflection && through_reflection
137
- super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' where the :through association '#{owner_class_name}##{through_reflection.name}' is a collection. Specify a has_one or belongs_to association in the :through option instead.")
138
- else
139
- super("Cannot have a has_one :through association.")
140
- end
141
- end
142
- end
143
-
144
- class HasOneAssociationPolymorphicThroughError < ActiveRecordError # :nodoc:
145
- def initialize(owner_class_name = nil, reflection = nil)
146
- if owner_class_name && reflection
147
- super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
148
- else
149
- super("Cannot have a has_one :through association.")
150
- end
151
- end
152
- end
153
-
154
- class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError # :nodoc:
155
- def initialize(reflection = nil)
156
- if reflection
157
- through_reflection = reflection.through_reflection
158
- source_reflection_names = reflection.source_reflection_names
159
- source_associations = reflection.through_reflection.klass._reflections.keys
160
- super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')}?")
161
- else
162
- super("Could not find the source association(s).")
163
- end
164
- end
165
- end
166
-
167
- class HasManyThroughOrderError < ActiveRecordError # :nodoc:
168
- def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
169
- if owner_class_name && reflection && through_reflection
170
- super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through '#{owner_class_name}##{through_reflection.name}' before the through association is defined.")
171
- else
172
- super("Cannot have a has_many :through association before the through association is defined.")
173
- end
174
- end
175
- end
176
-
177
- class ThroughCantAssociateThroughHasOneOrManyReflection < ActiveRecordError # :nodoc:
178
- def initialize(owner = nil, reflection = nil)
179
- if owner && reflection
180
- super("Cannot modify association '#{owner.class.name}##{reflection.name}' because the source reflection class '#{reflection.source_reflection.class_name}' is associated to '#{reflection.through_reflection.class_name}' via :#{reflection.source_reflection.macro}.")
181
- else
182
- super("Cannot modify association.")
183
- end
184
- end
185
- end
186
-
187
- class CompositePrimaryKeyMismatchError < ActiveRecordError # :nodoc:
188
- attr_reader :reflection
189
-
190
- def initialize(reflection = nil)
191
- if reflection
192
- if reflection.has_one? || reflection.collection?
193
- super("Association #{reflection.active_record}##{reflection.name} primary key #{reflection.active_record_primary_key} doesn't match with foreign key #{reflection.foreign_key}. Please specify query_constraints, or primary_key and foreign_key values.")
194
- else
195
- super("Association #{reflection.active_record}##{reflection.name} primary key #{reflection.association_primary_key} doesn't match with foreign key #{reflection.foreign_key}. Please specify query_constraints, or primary_key and foreign_key values.")
196
- end
197
- else
198
- super("Association primary key doesn't match with foreign key.")
199
- end
200
- end
201
- end
202
-
203
- class AmbiguousSourceReflectionForThroughAssociation < ActiveRecordError # :nodoc:
204
- def initialize(klass, macro, association_name, options, possible_sources)
205
- example_options = options.dup
206
- example_options[:source] = possible_sources.first
207
-
208
- super("Ambiguous source reflection for through association. Please " \
209
- "specify a :source directive on your declaration like:\n" \
210
- "\n" \
211
- " class #{klass} < ActiveRecord::Base\n" \
212
- " #{macro} :#{association_name}, #{example_options}\n" \
213
- " end"
214
- )
215
- end
216
- end
217
-
218
- class HasManyThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection # :nodoc:
219
- end
220
-
221
- class HasOneThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection # :nodoc:
222
- end
223
-
224
- class ThroughNestedAssociationsAreReadonly < ActiveRecordError # :nodoc:
225
- def initialize(owner = nil, reflection = nil)
226
- if owner && reflection
227
- super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
228
- else
229
- super("Through nested associations are read-only.")
230
- end
231
- end
232
- end
233
-
234
- class HasManyThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly # :nodoc:
235
- end
236
-
237
- class HasOneThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly # :nodoc:
238
- end
239
-
240
- # This error is raised when trying to eager load a polymorphic association using a JOIN.
241
- # Eager loading polymorphic associations is only possible with
242
- # {ActiveRecord::Relation#preload}[rdoc-ref:QueryMethods#preload].
243
- class EagerLoadPolymorphicError < ActiveRecordError
244
- def initialize(reflection = nil)
245
- if reflection
246
- super("Cannot eagerly load the polymorphic association #{reflection.name.inspect}")
247
- else
248
- super("Eager load polymorphic error.")
249
- end
250
- end
251
- end
252
-
253
- # This error is raised when trying to destroy a parent instance in N:1 or 1:1 associations
254
- # (has_many, has_one) when there is at least 1 child associated instance.
255
- # ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
256
- class DeleteRestrictionError < ActiveRecordError # :nodoc:
257
- def initialize(name = nil)
258
- if name
259
- super("Cannot delete record because of dependent #{name}")
260
- else
261
- super("Delete restriction error.")
262
- end
263
- end
264
- end
265
-
266
4
  # See ActiveRecord::Associations::ClassMethods for documentation.
267
5
  module Associations # :nodoc:
268
6
  extend ActiveSupport::Autoload
@@ -301,6 +39,8 @@ module ActiveRecord
301
39
  autoload :AssociationScope
302
40
  autoload :DisableJoinsAssociationScope
303
41
  autoload :AliasTracker
42
+
43
+ autoload :Deprecation
304
44
  end
305
45
 
306
46
  def self.eager_load!
@@ -341,7 +81,7 @@ module ActiveRecord
341
81
 
342
82
  # Returns the specified association instance if it exists, +nil+ otherwise.
343
83
  def association_instance_get(name)
344
- @association_cache[name]
84
+ (@association_cache ||= {})[name]
345
85
  end
346
86
 
347
87
  # Set the specified association instance.
@@ -349,6 +89,14 @@ module ActiveRecord
349
89
  @association_cache[name] = association
350
90
  end
351
91
 
92
+ def deprecated_associations_api_guard(association, method_name)
93
+ Deprecation.guard(association.reflection) { "the method #{method_name} was invoked" }
94
+ end
95
+
96
+ def report_deprecated_association(reflection, context:)
97
+ Deprecation.report(reflection, context: context)
98
+ end
99
+
352
100
  # = Active Record \Associations
353
101
  #
354
102
  # \Associations are a set of macro-like class methods for tying objects together through
@@ -641,21 +389,43 @@ module ActiveRecord
641
389
  # after_add: :congratulate_client,
642
390
  # after_remove: :log_after_remove
643
391
  #
644
- # def congratulate_client(record)
392
+ # def congratulate_client(client)
645
393
  # # ...
646
394
  # end
647
395
  #
648
- # def log_after_remove(record)
396
+ # def log_after_remove(client)
649
397
  # # ...
650
398
  # end
651
399
  # end
652
400
  #
401
+ # Callbacks can be defined in three ways:
402
+ #
403
+ # 1. A symbol that references a method defined on the class with the
404
+ # associated collection. For example, <tt>after_add: :congratulate_client</tt>
405
+ # invokes <tt>Firm#congratulate_client(client)</tt>.
406
+ # 2. A callable with a signature that accepts both the record with the
407
+ # associated collection and the record being added or removed. For
408
+ # example, <tt>after_add: ->(firm, client) { ... }</tt>.
409
+ # 3. An object that responds to the callback name. For example, passing
410
+ # <tt>after_add: CallbackObject.new</tt> invokes <tt>CallbackObject#after_add(firm,
411
+ # client)</tt>.
412
+ #
653
413
  # It's possible to stack callbacks by passing them as an array. Example:
654
414
  #
415
+ # class CallbackObject
416
+ # def after_add(firm, client)
417
+ # firm.log << "after_adding #{client.id}"
418
+ # end
419
+ # end
420
+ #
655
421
  # class Firm < ActiveRecord::Base
656
422
  # has_many :clients,
657
423
  # dependent: :destroy,
658
- # after_add: [:congratulate_client, -> (firm, record) { firm.log << "after_adding#{record.id}" }],
424
+ # after_add: [
425
+ # :congratulate_client,
426
+ # -> (firm, client) { firm.log << "after_adding #{client.id}" },
427
+ # CallbackObject.new
428
+ # ],
659
429
  # after_remove: :log_after_remove
660
430
  # end
661
431
  #
@@ -799,7 +569,7 @@ module ActiveRecord
799
569
  # @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
800
570
  # @group.avatars.delete(@group.avatars.last) # so would this
801
571
  #
802
- # == Setting Inverses
572
+ # === Setting Inverses
803
573
  #
804
574
  # If you are using a #belongs_to on the join model, it is a good idea to set the
805
575
  # <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example
@@ -1260,6 +1030,116 @@ module ActiveRecord
1260
1030
  # associated records themselves, you can always do something along the lines of
1261
1031
  # <tt>person.tasks.each(&:destroy)</tt>.
1262
1032
  #
1033
+ # == Deprecated \Associations
1034
+ #
1035
+ # \Associations can be marked as deprecated by passing <tt>deprecated: true</tt>:
1036
+ #
1037
+ # has_many :posts, deprecated: true
1038
+ #
1039
+ # When a deprecated association is used, a warning is issued using the
1040
+ # Active Record logger, though more options are available via
1041
+ # configuration.
1042
+ #
1043
+ # The message includes some context that helps understand the deprecated
1044
+ # usage:
1045
+ #
1046
+ # The association Author#posts is deprecated, the method post_ids was invoked (...)
1047
+ # The association Author#posts is deprecated, referenced in query to preload records (...)
1048
+ #
1049
+ # The dots in the examples above would have the application-level spot
1050
+ # where usage occurred, to help locate what triggered the warning. That
1051
+ # location is computed using the Active Record backtrace cleaner.
1052
+ #
1053
+ # === What is considered to be usage?
1054
+ #
1055
+ # * Invocation of any association methods like +posts+, <tt>posts=</tt>,
1056
+ # etc.
1057
+ #
1058
+ # * If the association accepts nested attributes, assignment to those
1059
+ # attributes.
1060
+ #
1061
+ # * If the association is a through association and some of its nested
1062
+ # associations are deprecated, you'll get warnings for them whenever the
1063
+ # top-level through is used. This is so regardless of whether the
1064
+ # through itself is deprecated.
1065
+ #
1066
+ # * Execution of queries that refer to the association. Think execution of
1067
+ # <tt>eager_load(:posts)</tt>, <tt>joins(author: :posts)</tt>, etc.
1068
+ #
1069
+ # * If the association has a +:dependent+ option, destroying the
1070
+ # associated record issues warnings (because that has a side-effect that
1071
+ # would not happen if the association was removed).
1072
+ #
1073
+ # * If the association has a +:touch+ option, saving or destroying the
1074
+ # record issues a warning (because that has a side-effect that would not
1075
+ # happen if the association was removed).
1076
+ #
1077
+ # === Things that do NOT issue warnings
1078
+ #
1079
+ # The rationale behind most of the following edge cases is that Active
1080
+ # Record accesses associations lazily, when used. Before that, the
1081
+ # reference to the association is basically just a Ruby symbol.
1082
+ #
1083
+ # * If +posts+ is deprecated, <tt>has_many :comments, through: :posts</tt>
1084
+ # does not warn. Usage of the +comments+ association reports usage of
1085
+ # +posts+, as we explained above, but the definition of the +has_many+
1086
+ # itself does not.
1087
+ #
1088
+ # * Similarly, <tt>accepts_nested_attributes_for :posts</tt> does not
1089
+ # warn. Assignment to the posts attributes warns, as explained above,
1090
+ # but the +accepts_nested_attributes_for+ call itself does not.
1091
+ #
1092
+ # * Same if an association declares to be inverse of a deprecated one, the
1093
+ # macro itself does not warn.
1094
+ #
1095
+ # * In the same line, the declaration <tt>validates_associated :posts</tt>
1096
+ # does not warn by itself, though access is reported when the validation
1097
+ # runs.
1098
+ #
1099
+ # * Relation query methods like <tt>Author.includes(:posts)</tt> do not
1100
+ # warn by themselves. At that point, that is a relation that internally
1101
+ # stores a symbol for later use. As explained in the previous section,
1102
+ # you get a warning when/if the query is executed.
1103
+ #
1104
+ # * Access to the reflection object of the association as in
1105
+ # <tt>Author.reflect_on_association(:posts)</tt> or
1106
+ # <tt>Author.reflect_on_all_associations</tt> does not warn.
1107
+ #
1108
+ # === Configuration
1109
+ #
1110
+ # Reporting deprecated usage can be configured:
1111
+ #
1112
+ # config.active_record.deprecated_associations_options = { ... }
1113
+ #
1114
+ # If present, this has to be a hash with keys +:mode+ and/or +:backtrace+.
1115
+ #
1116
+ # ==== Mode
1117
+ #
1118
+ # * In +:warn+ mode, usage issues a warning that includes the
1119
+ # application-level place where the access happened, if any. This is the
1120
+ # default mode.
1121
+ #
1122
+ # * In +:raise+ mode, usage raises an
1123
+ # ActiveRecord::DeprecatedAssociationError with a similar message and a
1124
+ # clean backtrace in the exception object.
1125
+ #
1126
+ # * In +:notify+ mode, a <tt>deprecated_association.active_record</tt>
1127
+ # Active Support notification is published. The event payload has the
1128
+ # association reflection (+:reflection+), the application-level location
1129
+ # (+:location+) where the access happened (a Thread::Backtrace::Location
1130
+ # object, or +nil+), and a deprecation message (+:message+).
1131
+ #
1132
+ # ==== Backtrace
1133
+ #
1134
+ # If +:backtrace+ is true, warnings include a clean backtrace in the message
1135
+ # and notifications have a +:backtrace+ key in the payload with an array
1136
+ # of clean Thread::Backtrace::Location objects. Exceptions always get a
1137
+ # clean stack trace set.
1138
+ #
1139
+ # Clean backtraces are computed using the Active Record backtrace cleaner.
1140
+ # In Rails applications, that is by the default the same as
1141
+ # <tt>Rails.backtrace_cleaner</tt>.
1142
+ #
1263
1143
  # == Type safety with ActiveRecord::AssociationTypeMismatch
1264
1144
  #
1265
1145
  # If you attempt to assign an object to an association that doesn't match the inferred
@@ -1448,8 +1328,10 @@ module ActiveRecord
1448
1328
  # [+:as+]
1449
1329
  # Specifies a polymorphic interface (See #belongs_to).
1450
1330
  # [+:through+]
1451
- # Specifies an association through which to perform the query. This can be any other type
1452
- # of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>,
1331
+ # Specifies an association through which to perform the query.
1332
+ #
1333
+ # This can be any other type of association, including other <tt>:through</tt> associations,
1334
+ # but it cannot be a polymorphic association. Options for <tt>:class_name</tt>,
1453
1335
  # <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
1454
1336
  # source reflection.
1455
1337
  #
@@ -1461,8 +1343,11 @@ module ActiveRecord
1461
1343
  # If you are going to modify the association (rather than just read from it), then it is
1462
1344
  # a good idea to set the <tt>:inverse_of</tt> option on the source association on the
1463
1345
  # join model. This allows associated records to be built which will automatically create
1464
- # the appropriate join model records when they are saved. (See the 'Association Join Models'
1465
- # and 'Setting Inverses' sections above.)
1346
+ # the appropriate join model records when they are saved. See
1347
+ # {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
1348
+ # and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
1349
+ # more detail.
1350
+ #
1466
1351
  # [+:disable_joins+]
1467
1352
  # Specifies whether joins should be skipped for an association. If set to true, two or more queries
1468
1353
  # will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
@@ -1491,7 +1376,8 @@ module ActiveRecord
1491
1376
  # [+:inverse_of+]
1492
1377
  # Specifies the name of the #belongs_to association on the associated object
1493
1378
  # that is the inverse of this #has_many association.
1494
- # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1379
+ # See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
1380
+ # for more detail.
1495
1381
  # [+:extend+]
1496
1382
  # Specifies a module or array of modules that will be extended into the association object returned.
1497
1383
  # Useful for defining methods on associations, especially when they should be shared between multiple
@@ -1507,10 +1393,23 @@ module ActiveRecord
1507
1393
  # This is an optional option. By default Rails will attempt to derive the value automatically.
1508
1394
  # When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
1509
1395
  # [+:index_errors+]
1510
- # Enables differentiation of multiple validation errors from the association records, by including
1396
+ # Allows differentiation of multiple validation errors from the association records, by including
1511
1397
  # an index in the error attribute name, e.g. +roles[2].level+.
1512
- # The index is based on association order, i.e. database order, with yet to be
1398
+ # When set to +true+, the index is based on association order, i.e. database order, with yet to be
1513
1399
  # persisted new records placed at the end.
1400
+ # When set to +:nested_attributes_order+, the index is based on the record order received by
1401
+ # nested attributes setter, when accepts_nested_attributes_for is used.
1402
+ # [:before_add]
1403
+ # Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>before an object is added</b> to the association collection.
1404
+ # [:after_add]
1405
+ # Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>after an object is added</b> to the association collection.
1406
+ # [:before_remove]
1407
+ # Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>before an object is removed</b> from the association collection.
1408
+ # [:after_remove]
1409
+ # Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>after an object is removed</b> from the association collection.
1410
+ # [+:deprecated+]
1411
+ # If true, marks the association as deprecated. Usage of deprecated associations is reported.
1412
+ # Please, check the class documentation above for details.
1514
1413
  #
1515
1414
  # Option examples:
1516
1415
  # has_many :comments, -> { order("posted_on") }
@@ -1524,16 +1423,18 @@ module ActiveRecord
1524
1423
  # has_many :subscribers, through: :subscriptions, disable_joins: true
1525
1424
  # has_many :comments, strict_loading: true
1526
1425
  # has_many :comments, query_constraints: [:blog_id, :post_id]
1527
- # has_many :comments, index_errors: true
1426
+ # has_many :comments, index_errors: :nested_attributes_order
1528
1427
  def has_many(name, scope = nil, **options, &extension)
1529
1428
  reflection = Builder::HasMany.build(self, name, scope, options, &extension)
1530
- Reflection.add_reflection self, name, reflection
1429
+ Reflection.add_reflection(self, name, reflection)
1531
1430
  end
1532
1431
 
1533
- # Specifies a one-to-one association with another class. This method should only be used
1534
- # if the other class contains the foreign key. If the current class contains the foreign key,
1535
- # then you should use #belongs_to instead. See also ActiveRecord::Associations::ClassMethods's overview
1536
- # on when to use #has_one and when to use #belongs_to.
1432
+ # Specifies a one-to-one association with another class. This method
1433
+ # should only be used if the other class contains the foreign key. If
1434
+ # the current class contains the foreign key, then you should use
1435
+ # #belongs_to instead. See {Is it a belongs_to or has_one
1436
+ # association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
1437
+ # for more detail on when to use #has_one and when to use #belongs_to.
1537
1438
  #
1538
1439
  # The following methods for retrieval and query of a single associated object will be added:
1539
1440
  #
@@ -1635,10 +1536,12 @@ module ActiveRecord
1635
1536
  # [+:as+]
1636
1537
  # Specifies a polymorphic interface (See #belongs_to).
1637
1538
  # [+:through+]
1638
- # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
1639
- # <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
1640
- # source reflection. You can only use a <tt>:through</tt> query through a #has_one
1641
- # or #belongs_to association on the join model.
1539
+ # Specifies an association through which to perform the query.
1540
+ #
1541
+ # The through association must be a +has_one+, <tt>has_one :through</tt>, or non-polymorphic +belongs_to+.
1542
+ # That is, a non-polymorphic singular association. Options for <tt>:class_name</tt>, <tt>:primary_key</tt>,
1543
+ # and <tt>:foreign_key</tt> are ignored, as the association uses the source reflection. You can only
1544
+ # use a <tt>:through</tt> query through a #has_one or #belongs_to association on the join model.
1642
1545
  #
1643
1546
  # If the association on the join model is a #belongs_to, the collection can be modified
1644
1547
  # and the records on the <tt>:through</tt> model will be automatically created and removed
@@ -1648,8 +1551,10 @@ module ActiveRecord
1648
1551
  # If you are going to modify the association (rather than just read from it), then it is
1649
1552
  # a good idea to set the <tt>:inverse_of</tt> option on the source association on the
1650
1553
  # join model. This allows associated records to be built which will automatically create
1651
- # the appropriate join model records when they are saved. (See the 'Association Join Models'
1652
- # and 'Setting Inverses' sections above.)
1554
+ # the appropriate join model records when they are saved. See
1555
+ # {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
1556
+ # and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
1557
+ # more detail.
1653
1558
  # [+:disable_joins+]
1654
1559
  # Specifies whether joins should be skipped for an association. If set to true, two or more queries
1655
1560
  # will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
@@ -1667,9 +1572,14 @@ module ActiveRecord
1667
1572
  # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
1668
1573
  # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
1669
1574
  # [+:autosave+]
1670
- # If true, always save the associated object or destroy it if marked for destruction,
1671
- # when saving the parent object. If false, never save or destroy the associated object.
1672
- # By default, only save the associated object if it's a new record.
1575
+ # If +true+, always saves the associated object or destroys it if marked for destruction,
1576
+ # when saving the parent object.
1577
+ # If +false+, never save or destroy the associated object.
1578
+ #
1579
+ # By default, only saves the associated object if it's a new record. Setting this option
1580
+ # to +true+ also enables validations on the associated object unless explicitly disabled
1581
+ # with <tt>validate: false</tt>. This is because saving an object with invalid associated
1582
+ # objects would fail, so any associated objects will go through validation checks.
1673
1583
  #
1674
1584
  # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
1675
1585
  # <tt>:autosave</tt> to <tt>true</tt>.
@@ -1682,7 +1592,8 @@ module ActiveRecord
1682
1592
  # [+:inverse_of+]
1683
1593
  # Specifies the name of the #belongs_to association on the associated object
1684
1594
  # that is the inverse of this #has_one association.
1685
- # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1595
+ # See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
1596
+ # for more detail.
1686
1597
  # [+:required+]
1687
1598
  # When set to +true+, the association will also have its presence validated.
1688
1599
  # This will validate the association itself, not the id. You can use
@@ -1696,12 +1607,15 @@ module ActiveRecord
1696
1607
  # Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
1697
1608
  # This is an optional option. By default Rails will attempt to derive the value automatically.
1698
1609
  # When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
1610
+ # [+:deprecated+]
1611
+ # If true, marks the association as deprecated. Usage of deprecated associations is reported.
1612
+ # Please, check the class documentation above for details.
1699
1613
  #
1700
1614
  # Option examples:
1701
1615
  # has_one :credit_card, dependent: :destroy # destroys the associated credit card
1702
1616
  # has_one :credit_card, dependent: :nullify # updates the associated records foreign
1703
1617
  # # key value to NULL rather than destroying it
1704
- # has_one :last_comment, -> { order('posted_on') }, class_name: "Comment"
1618
+ # has_one :last_comment, -> { order('posted_on desc') }, class_name: "Comment"
1705
1619
  # has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person"
1706
1620
  # has_one :attachment, as: :attachable
1707
1621
  # has_one :boss, -> { readonly }
@@ -1713,13 +1627,15 @@ module ActiveRecord
1713
1627
  # has_one :employment_record_book, query_constraints: [:organization_id, :employee_id]
1714
1628
  def has_one(name, scope = nil, **options)
1715
1629
  reflection = Builder::HasOne.build(self, name, scope, options)
1716
- Reflection.add_reflection self, name, reflection
1630
+ Reflection.add_reflection(self, name, reflection)
1717
1631
  end
1718
1632
 
1719
- # Specifies a one-to-one association with another class. This method should only be used
1720
- # if this class contains the foreign key. If the other class contains the foreign key,
1721
- # then you should use #has_one instead. See also ActiveRecord::Associations::ClassMethods's overview
1722
- # on when to use #has_one and when to use #belongs_to.
1633
+ # Specifies a one-to-one association with another class. This method
1634
+ # should only be used if this class contains the foreign key. If the
1635
+ # other class contains the foreign key, then you should use #has_one
1636
+ # instead. See {Is it a belongs_to or has_one
1637
+ # association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
1638
+ # for more detail on when to use #has_one and when to use #belongs_to.
1723
1639
  #
1724
1640
  # Methods will be added for retrieval and query for a single associated object, for which
1725
1641
  # this object holds an id:
@@ -1790,7 +1706,9 @@ module ActiveRecord
1790
1706
  # [+:class_name+]
1791
1707
  # Specify the class name of the association. Use it only if that name can't be inferred
1792
1708
  # from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
1793
- # if the real class name is Person, you'll have to specify it with this option.
1709
+ # if the real class name is Person, you'll have to specify it with this option. +:class_name+
1710
+ # is not supported in polymorphic associations, since in that case the class name of the
1711
+ # associated record is stored in the type column.
1794
1712
  # [+:foreign_key+]
1795
1713
  # Specify the foreign key used for the association. By default this is guessed to be the name
1796
1714
  # of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
@@ -1822,15 +1740,25 @@ module ActiveRecord
1822
1740
  # named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
1823
1741
  # is used on the associate class (such as a Post class) - that is the migration for
1824
1742
  # <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
1825
- # return the count cached, see note below). You can also specify a custom counter
1743
+ # return the count cached). You can also specify a custom counter
1826
1744
  # cache column by providing a column name instead of a +true+/+false+ value to this
1827
1745
  # option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
1828
- # Note: Specifying a counter cache will add it to that model's list of readonly attributes
1829
- # using +attr_readonly+.
1830
- # [+:polymorphic+]
1831
- # Specify this association is a polymorphic association by passing +true+.
1746
+ #
1747
+ # Starting to use counter caches on existing large tables can be troublesome, because the column
1748
+ # values must be backfilled separately of the column addition (to not lock the table for too long)
1749
+ # and before the use of +:counter_cache+ (otherwise methods like +size+/+any?+/etc, which use
1750
+ # counter caches internally, can produce incorrect results). To safely backfill the values while keeping
1751
+ # counter cache columns updated with the child records creation/removal and to avoid the mentioned methods
1752
+ # use the possibly incorrect counter cache column values and always get the results from the database,
1753
+ # use <tt>counter_cache: { active: false }</tt>.
1754
+ # If you also need to specify a custom column name, use <tt>counter_cache: { active: false, column: :my_custom_counter }</tt>.
1755
+ #
1832
1756
  # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
1833
1757
  # to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
1758
+ # [+:polymorphic+]
1759
+ # Specify this association is a polymorphic association by passing +true+.
1760
+ # Note: Since polymorphic associations rely on storing class names in the database, make sure to update the class names in the
1761
+ # <tt>*_type</tt> polymorphic type column of the corresponding rows.
1834
1762
  # [+:validate+]
1835
1763
  # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
1836
1764
  # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
@@ -1851,7 +1779,8 @@ module ActiveRecord
1851
1779
  # [+:inverse_of+]
1852
1780
  # Specifies the name of the #has_one or #has_many association on the associated
1853
1781
  # object that is the inverse of this #belongs_to association.
1854
- # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1782
+ # See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
1783
+ # for more detail.
1855
1784
  # [+:optional+]
1856
1785
  # When set to +true+, the association will not have its presence validated.
1857
1786
  # [+:required+]
@@ -1873,6 +1802,9 @@ module ActiveRecord
1873
1802
  # Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
1874
1803
  # This is an optional option. By default Rails will attempt to derive the value automatically.
1875
1804
  # When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
1805
+ # [+:deprecated+]
1806
+ # If true, marks the association as deprecated. Usage of deprecated associations is reported.
1807
+ # Please, check the class documentation above for details.
1876
1808
  #
1877
1809
  # Option examples:
1878
1810
  # belongs_to :firm, foreign_key: "client_of"
@@ -1888,10 +1820,10 @@ module ActiveRecord
1888
1820
  # belongs_to :user, optional: true
1889
1821
  # belongs_to :account, default: -> { company.account }
1890
1822
  # belongs_to :account, strict_loading: true
1891
- # belong_to :note, query_constraints: [:organization_id, :note_id]
1823
+ # belongs_to :note, query_constraints: [:organization_id, :note_id]
1892
1824
  def belongs_to(name, scope = nil, **options)
1893
1825
  reflection = Builder::BelongsTo.build(self, name, scope, options)
1894
- Reflection.add_reflection self, name, reflection
1826
+ Reflection.add_reflection(self, name, reflection)
1895
1827
  end
1896
1828
 
1897
1829
  # Specifies a many-to-many relationship with another class. This associates two classes via an
@@ -1911,7 +1843,7 @@ module ActiveRecord
1911
1843
  # The join table should not have a primary key or a model associated with it. You must manually generate the
1912
1844
  # join table with a migration such as this:
1913
1845
  #
1914
- # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[7.1]
1846
+ # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[8.1]
1915
1847
  # def change
1916
1848
  # create_join_table :developers, :projects
1917
1849
  # end
@@ -2062,6 +1994,9 @@ module ActiveRecord
2062
1994
  # <tt>:autosave</tt> to <tt>true</tt>.
2063
1995
  # [+:strict_loading+]
2064
1996
  # Enforces strict loading every time an associated record is loaded through this association.
1997
+ # [+:deprecated+]
1998
+ # If true, marks the association as deprecated. Usage of deprecated associations is reported.
1999
+ # Please, check the class documentation above for details.
2065
2000
  #
2066
2001
  # Option examples:
2067
2002
  # has_and_belongs_to_many :projects
@@ -2073,17 +2008,17 @@ module ActiveRecord
2073
2008
  def has_and_belongs_to_many(name, scope = nil, **options, &extension)
2074
2009
  habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
2075
2010
 
2076
- builder = Builder::HasAndBelongsToMany.new name, self, options
2011
+ builder = Builder::HasAndBelongsToMany.new(name, self, options)
2077
2012
 
2078
2013
  join_model = builder.through_model
2079
2014
 
2080
- const_set join_model.name, join_model
2081
- private_constant join_model.name
2015
+ const_set(join_model.name, join_model)
2016
+ private_constant(join_model.name)
2082
2017
 
2083
- middle_reflection = builder.middle_reflection join_model
2018
+ middle_reflection = builder.middle_reflection(join_model)
2084
2019
 
2085
- Builder::HasMany.define_callbacks self, middle_reflection
2086
- Reflection.add_reflection self, middle_reflection.name, middle_reflection
2020
+ Builder::HasMany.define_callbacks(self, middle_reflection)
2021
+ Reflection.add_reflection(self, middle_reflection.name, middle_reflection)
2087
2022
  middle_reflection.parent_reflection = habtm_reflection
2088
2023
 
2089
2024
  include Module.new {
@@ -2100,12 +2035,12 @@ module ActiveRecord
2100
2035
  hm_options[:through] = middle_reflection.name
2101
2036
  hm_options[:source] = join_model.right_reflection.name
2102
2037
 
2103
- [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading].each do |k|
2104
- hm_options[k] = options[k] if options.key? k
2038
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading, :deprecated].each do |k|
2039
+ hm_options[k] = options[k] if options.key?(k)
2105
2040
  end
2106
2041
 
2107
2042
  has_many name, scope, **hm_options, &extension
2108
- _reflections[name.to_s].parent_reflection = habtm_reflection
2043
+ _reflections[name].parent_reflection = habtm_reflection
2109
2044
  end
2110
2045
  end
2111
2046
  end