activerecord 7.1.3 → 7.1.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +324 -0
- data/lib/active_record/associations/belongs_to_association.rb +4 -4
- data/lib/active_record/associations/collection_association.rb +4 -4
- data/lib/active_record/associations/has_many_association.rb +2 -2
- data/lib/active_record/associations/has_one_association.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +10 -12
- data/lib/active_record/associations.rb +6 -0
- data/lib/active_record/attribute_methods/dirty.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +3 -3
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +46 -6
- data/lib/active_record/autosave_association.rb +5 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +8 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +8 -4
- data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -15
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +37 -13
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -10
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -2
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +16 -20
- data/lib/active_record/core.rb +8 -3
- data/lib/active_record/counter_cache.rb +7 -3
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/hash_config.rb +6 -2
- data/lib/active_record/delegated_type.rb +6 -6
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- data/lib/active_record/encryption/scheme.rb +8 -4
- data/lib/active_record/encryption.rb +2 -0
- data/lib/active_record/enum.rb +1 -1
- data/lib/active_record/future_result.rb +9 -0
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/compatibility.rb +6 -0
- data/lib/active_record/model_schema.rb +7 -2
- data/lib/active_record/nested_attributes.rb +13 -2
- data/lib/active_record/persistence.rb +2 -2
- data/lib/active_record/query_cache.rb +1 -1
- data/lib/active_record/query_logs_formatter.rb +1 -1
- data/lib/active_record/railtie.rb +14 -14
- data/lib/active_record/railties/databases.rake +2 -2
- data/lib/active_record/reflection.rb +8 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +6 -1
- data/lib/active_record/relation/query_methods.rb +21 -7
- data/lib/active_record/relation.rb +13 -3
- data/lib/active_record/result.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +30 -8
- data/lib/active_record/test_fixtures.rb +1 -0
- data/lib/active_record/timestamp.rb +3 -1
- data/lib/active_record.rb +2 -2
- data/lib/arel/tree_manager.rb +5 -1
- data/lib/arel/visitors/to_sql.rb +2 -1
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53c82b47d80060218db2fd5a44483fe30a9ce2a7e235c30e894d4d6a9c0e7d35
|
4
|
+
data.tar.gz: b5432955eae8f100ceb96c40759de6932288b1aedf78d6c4b08cfb223b7adb8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 935ee9fbc8c855663b10de47bffa2b7d51328a9cc7575f4aa5c9b26eaf0cc1ed9c4271e3c3f5982ceafbb00a679b0262b18782f165b31454fafc4ce6966b1575
|
7
|
+
data.tar.gz: 53dba913a6174f80766bc995dcfad80c1fbdf2f461474ed8b7e13a1cc8e6a321076f1e74a8a5ace878fce08154dd3a6dff51263365d982d22be50bd4c928de9e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,327 @@
|
|
1
|
+
## Rails 7.1.5.1 (December 10, 2024) ##
|
2
|
+
|
3
|
+
* No changes.
|
4
|
+
|
5
|
+
|
6
|
+
## Rails 7.1.5 (October 30, 2024) ##
|
7
|
+
|
8
|
+
* Fix marshalling of unsaved associated records in 7.1 format.
|
9
|
+
|
10
|
+
The 7.1 format would only marshal associated records if the association was loaded.
|
11
|
+
But associations that would only contain unsaved records would be skipped.
|
12
|
+
|
13
|
+
*Jean Boussier*
|
14
|
+
|
15
|
+
* Fix an issue where `.left_outer_joins` used with multiple associations that have
|
16
|
+
the same child association but different parents does not join all parents.
|
17
|
+
|
18
|
+
Previously, using `.left_outer_joins` with the same child association would only join one of the parents.
|
19
|
+
|
20
|
+
Now it will correctly join both parents.
|
21
|
+
|
22
|
+
Fixes #41498.
|
23
|
+
|
24
|
+
*Garrett Blehm*
|
25
|
+
|
26
|
+
* Ensure `ActiveRecord::Encryption.config` is always ready before access.
|
27
|
+
|
28
|
+
Previously, `ActiveRecord::Encryption` configuration was deferred until `ActiveRecord::Base`
|
29
|
+
was loaded. Therefore, accessing `ActiveRecord::Encryption.config` properties before
|
30
|
+
`ActiveRecord::Base` was loaded would give incorrect results.
|
31
|
+
|
32
|
+
`ActiveRecord::Encryption` now has its own loading hook so that its configuration is set as
|
33
|
+
soon as needed.
|
34
|
+
|
35
|
+
When `ActiveRecord::Base` is loaded, even lazily, it in turn triggers the loading of
|
36
|
+
`ActiveRecord::Encryption`, thus preserving the original behavior of having its config ready
|
37
|
+
before any use of `ActiveRecord::Base`.
|
38
|
+
|
39
|
+
*Maxime Réty*
|
40
|
+
|
41
|
+
* Add `TimeZoneConverter#==` method, so objects will be properly compared by
|
42
|
+
their type, scale, limit & precision.
|
43
|
+
|
44
|
+
Address #52699.
|
45
|
+
|
46
|
+
*Ruy Rocha*
|
47
|
+
|
48
|
+
|
49
|
+
## Rails 7.1.4.2 (October 23, 2024) ##
|
50
|
+
|
51
|
+
* No changes.
|
52
|
+
|
53
|
+
|
54
|
+
## Rails 7.1.4.1 (October 15, 2024) ##
|
55
|
+
|
56
|
+
* No changes.
|
57
|
+
|
58
|
+
|
59
|
+
## Rails 7.1.4 (August 22, 2024) ##
|
60
|
+
|
61
|
+
* Allow to eager load nested nil associations.
|
62
|
+
|
63
|
+
*fatkodima*
|
64
|
+
|
65
|
+
* Fix `create_table` with `:auto_increment` option for MySQL adapter.
|
66
|
+
|
67
|
+
*fatkodima*
|
68
|
+
|
69
|
+
* Don't load has_one associations during autosave.
|
70
|
+
|
71
|
+
*Eugene Kenny*
|
72
|
+
|
73
|
+
* Fix migration ordering for `bin/rails db:prepare` across databases.
|
74
|
+
|
75
|
+
*fatkodima*
|
76
|
+
|
77
|
+
* Fix `alias_attribute` to ignore methods defined in parent classes.
|
78
|
+
|
79
|
+
*Jean Boussier*
|
80
|
+
|
81
|
+
* Fix a performance regression in attribute methods.
|
82
|
+
|
83
|
+
*Jean Boussier*
|
84
|
+
|
85
|
+
* Fix Active Record configs variable shadowing.
|
86
|
+
|
87
|
+
*Joel Lubrano*
|
88
|
+
|
89
|
+
* Fix running migrations on other databases when `database_tasks: false` on primary.
|
90
|
+
|
91
|
+
*fatkodima*
|
92
|
+
|
93
|
+
* Fix non-partial inserts for models with composite identity primary keys.
|
94
|
+
|
95
|
+
*fatkodima*
|
96
|
+
|
97
|
+
* Fix `ActiveRecord::Relation#touch_all` with custom attribute aliased as attribute for update.
|
98
|
+
|
99
|
+
*fatkodima*
|
100
|
+
|
101
|
+
* Fix a crash when an Executor wrapped fork exit.
|
102
|
+
|
103
|
+
*Joé Dupuis*
|
104
|
+
|
105
|
+
* Fix `destroy_async` job for owners with composite primary keys.
|
106
|
+
|
107
|
+
*fatkodima*
|
108
|
+
|
109
|
+
* Ensure pre-7.1 migrations use legacy index names when using `rename_table`.
|
110
|
+
|
111
|
+
*fatkodima*
|
112
|
+
|
113
|
+
* Allow `primary_key:` association option to be composite.
|
114
|
+
|
115
|
+
*Nikita Vasilevsky*
|
116
|
+
|
117
|
+
* Do not try to alias on key update when raw SQL is supplied.
|
118
|
+
|
119
|
+
*Gabriel Amaral*
|
120
|
+
|
121
|
+
* Memoize `key_provider` from `key` or deterministic `key_provider` if any.
|
122
|
+
|
123
|
+
*Rosa Gutierrez*
|
124
|
+
|
125
|
+
* Fix `upsert` warning for MySQL.
|
126
|
+
|
127
|
+
*fatkodima*
|
128
|
+
|
129
|
+
* Fix predicate builder for polymorphic models referencing models with composite primary keys.
|
130
|
+
|
131
|
+
*fatkodima*
|
132
|
+
|
133
|
+
* Fix `update_all/delete_all` on CPK model relation with join subquery.
|
134
|
+
|
135
|
+
*Nikita Vasilevsky*
|
136
|
+
|
137
|
+
* Remove memoization to accept `key_provider` overridden by `with_encryption_context`.
|
138
|
+
|
139
|
+
*John Hawthorn*
|
140
|
+
|
141
|
+
* Raise error for Trilogy when prepared_statements is true.
|
142
|
+
|
143
|
+
Trilogy doesn't currently support prepared statements. The error that
|
144
|
+
applications would see is a `StatementInvalid` error. This doesn't quite point
|
145
|
+
you to the fact this isn't supported. So raise a more appropriate error
|
146
|
+
pointing to what to change.
|
147
|
+
|
148
|
+
*Eileen M. Uchitelle*
|
149
|
+
|
150
|
+
* Fix loading schema cache when all databases have disabled database tasks.
|
151
|
+
|
152
|
+
*fatkodima*
|
153
|
+
|
154
|
+
* Always request `primary_key` in `RETURNING` if no other columns requested.
|
155
|
+
|
156
|
+
*Nikita Vasilevsky*
|
157
|
+
|
158
|
+
* Handle records being loaded with Marshal without triggering schema load
|
159
|
+
|
160
|
+
When using the old marshalling format for Active Record and loading
|
161
|
+
a serialized instance, it didn't trigger loading the schema and defining
|
162
|
+
attribute methods.
|
163
|
+
|
164
|
+
*Jean Boussier*
|
165
|
+
|
166
|
+
* Prevent some constant redefinition warnings when defining `inherited` on models.
|
167
|
+
|
168
|
+
*Adrian Hirt*
|
169
|
+
|
170
|
+
* Fix a memory perfomance regression in attribute methods.
|
171
|
+
|
172
|
+
Attribute methods used much more memory and were slower to define than
|
173
|
+
they should have been.
|
174
|
+
|
175
|
+
*Jean Boussier*
|
176
|
+
|
177
|
+
* Fix an issue that could cause database connection leaks.
|
178
|
+
|
179
|
+
If Active Record successfully connected to the database, but then failed
|
180
|
+
to read the server informations, the connection would be leaked until the
|
181
|
+
Ruby garbage collector triggers.
|
182
|
+
|
183
|
+
*Jean Boussier*
|
184
|
+
|
185
|
+
* Fix an issue where the IDs reader method did not return expected results
|
186
|
+
for preloaded associations in models using composite primary keys.
|
187
|
+
|
188
|
+
*Jay Ang*
|
189
|
+
|
190
|
+
* PostgreSQL `Cidr#change?` detects the address prefix change.
|
191
|
+
|
192
|
+
*Taketo Takashima*
|
193
|
+
|
194
|
+
* Fix Active Record serialization to not include instantiated but not loaded associations
|
195
|
+
|
196
|
+
*Jean Boussier*, *Ben Kyriakou*
|
197
|
+
|
198
|
+
* Allow `Sqlite3Adapter` to use `sqlite3` gem version `2.x`
|
199
|
+
|
200
|
+
*Mike Dalessio*
|
201
|
+
|
202
|
+
* Strict loading using `:n_plus_one_only` does not eagerly load child associations.
|
203
|
+
|
204
|
+
With this change, child associations are no longer eagerly loaded, to
|
205
|
+
match intended behavior and to prevent non-deterministic order issues caused
|
206
|
+
by calling methods like `first` or `last`. As `first` and `last` don't cause
|
207
|
+
an N+1 by themselves, calling child associations will no longer raise.
|
208
|
+
Fixes #49473.
|
209
|
+
|
210
|
+
Before:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
person = Person.find(1)
|
214
|
+
person.strict_loading!(mode: :n_plus_one_only)
|
215
|
+
person.posts.first
|
216
|
+
# SELECT * FROM posts WHERE person_id = 1; -- non-deterministic order
|
217
|
+
person.posts.first.firm # raises ActiveRecord::StrictLoadingViolationError
|
218
|
+
```
|
219
|
+
|
220
|
+
After:
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
person = Person.find(1)
|
224
|
+
person.strict_loading!(mode: :n_plus_one_only)
|
225
|
+
person.posts.first # this is 1+1, not N+1
|
226
|
+
# SELECT * FROM posts WHERE person_id = 1 ORDER BY id LIMIT 1;
|
227
|
+
person.posts.first.firm # no longer raises
|
228
|
+
```
|
229
|
+
|
230
|
+
*Reid Lynch*
|
231
|
+
|
232
|
+
* Using `Model.query_constraints` with a single non-primary-key column used to raise as expected, but with an
|
233
|
+
incorrect error message. This has been fixed to raise with a more appropriate error message.
|
234
|
+
|
235
|
+
*Joshua Young*
|
236
|
+
|
237
|
+
* Fix `has_one` association autosave setting the foreign key attribute when it is unchanged.
|
238
|
+
|
239
|
+
This behaviour is also inconsistent with autosaving `belongs_to` and can have unintended side effects like raising
|
240
|
+
an `ActiveRecord::ReadonlyAttributeError` when the foreign key attribute is marked as read-only.
|
241
|
+
|
242
|
+
*Joshua Young*
|
243
|
+
|
244
|
+
* Fix an issue where `ActiveRecord::Encryption` configurations are not ready before the loading
|
245
|
+
of Active Record models, when an application is eager loaded. As a result, encrypted attributes
|
246
|
+
could be misconfigured in some cases.
|
247
|
+
|
248
|
+
*Maxime Réty*
|
249
|
+
|
250
|
+
* Properly synchronize `Mysql2Adapter#active?` and `TrilogyAdapter#active?`
|
251
|
+
|
252
|
+
As well as `disconnect!` and `verify!`.
|
253
|
+
|
254
|
+
This generally isn't a big problem as connections must not be shared between
|
255
|
+
threads, but is required when running transactional tests or system tests
|
256
|
+
and could lead to a SEGV.
|
257
|
+
|
258
|
+
*Jean Boussier*
|
259
|
+
|
260
|
+
* Fix counter caches when the foreign key is composite.
|
261
|
+
|
262
|
+
If the model holding the counter cache had a composite primary key,
|
263
|
+
inserting a dependent record would fail with an `ArgumentError`
|
264
|
+
`Expected corresponding value for...`
|
265
|
+
|
266
|
+
*fatkodima*
|
267
|
+
|
268
|
+
* Fix loading of schema cache for multiple databases.
|
269
|
+
|
270
|
+
Before this change, if you have multiple databases configured in your
|
271
|
+
application, and had schema cache present, Rails would load the same
|
272
|
+
cache to all databases.
|
273
|
+
|
274
|
+
*Rafael Mendonça França*
|
275
|
+
|
276
|
+
* Fix eager loading of composite primary key associations.
|
277
|
+
|
278
|
+
`relation.eager_load(:other_model)` could load the wrong records if `other_model`
|
279
|
+
had a composite primary key.
|
280
|
+
|
281
|
+
*Nikita Vasilevsky*
|
282
|
+
|
283
|
+
* Fix async queries returning a doubly wrapped result when hitting the query cache.
|
284
|
+
|
285
|
+
*fatkodima*
|
286
|
+
|
287
|
+
* Fix single quote escapes on default generated MySQL columns
|
288
|
+
|
289
|
+
MySQL 5.7.5+ supports generated columns, which can be used to create a column that is computed from an expression.
|
290
|
+
|
291
|
+
Previously, the schema dump would output a string with double escapes for generated columns with single quotes in the default expression.
|
292
|
+
|
293
|
+
This would result in issues when importing the schema on a fresh instance of a MySQL database.
|
294
|
+
|
295
|
+
Now, the string will not be escaped and will be valid Ruby upon importing of the schema.
|
296
|
+
|
297
|
+
*Yash Kapadia*
|
298
|
+
|
299
|
+
* Fix Migrations with versions older than 7.1 validating options given to
|
300
|
+
`t.references`.
|
301
|
+
|
302
|
+
*Hartley McGuire*
|
303
|
+
|
304
|
+
|
305
|
+
## Rails 7.1.3.4 (June 04, 2024) ##
|
306
|
+
|
307
|
+
* No changes.
|
308
|
+
|
309
|
+
|
310
|
+
## Rails 7.1.3.3 (May 16, 2024) ##
|
311
|
+
|
312
|
+
* No changes.
|
313
|
+
|
314
|
+
|
315
|
+
## Rails 7.1.3.2 (February 21, 2024) ##
|
316
|
+
|
317
|
+
* No changes.
|
318
|
+
|
319
|
+
|
320
|
+
## Rails 7.1.3.1 (February 21, 2024) ##
|
321
|
+
|
322
|
+
* No changes.
|
323
|
+
|
324
|
+
|
1
325
|
## Rails 7.1.3 (January 16, 2024) ##
|
2
326
|
|
3
327
|
* Fix Migrations with versions older than 7.1 validating options given to
|
@@ -12,11 +12,11 @@ module ActiveRecord
|
|
12
12
|
raise ActiveRecord::Rollback unless target.destroy
|
13
13
|
when :destroy_async
|
14
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
|
15
|
+
primary_key_column = reflection.active_record_primary_key
|
16
|
+
id = reflection.foreign_key.map { |col| owner.public_send(col) }
|
17
17
|
else
|
18
|
-
primary_key_column = reflection.active_record_primary_key
|
19
|
-
id = owner.public_send(reflection.foreign_key
|
18
|
+
primary_key_column = reflection.active_record_primary_key
|
19
|
+
id = owner.public_send(reflection.foreign_key)
|
20
20
|
end
|
21
21
|
|
22
22
|
enqueue_destroy_association(
|
@@ -48,11 +48,11 @@ module ActiveRecord
|
|
48
48
|
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
|
49
49
|
def ids_reader
|
50
50
|
if loaded?
|
51
|
-
target.pluck(reflection.association_primary_key)
|
51
|
+
target.pluck(*reflection.association_primary_key)
|
52
52
|
elsif !target.empty?
|
53
|
-
load_target.pluck(reflection.association_primary_key)
|
53
|
+
load_target.pluck(*reflection.association_primary_key)
|
54
54
|
else
|
55
|
-
@association_ids ||= scope.pluck(reflection.association_primary_key)
|
55
|
+
@association_ids ||= scope.pluck(*reflection.association_primary_key)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -303,7 +303,7 @@ module ActiveRecord
|
|
303
303
|
|
304
304
|
def find_from_target?
|
305
305
|
loaded? ||
|
306
|
-
owner.strict_loading? ||
|
306
|
+
(owner.strict_loading? && owner.strict_loading_all?) ||
|
307
307
|
reflection.strict_loading? ||
|
308
308
|
owner.new_record? ||
|
309
309
|
target.any? { |record| record.new_record? || record.changed? }
|
@@ -35,10 +35,10 @@ module ActiveRecord
|
|
35
35
|
unless target.empty?
|
36
36
|
association_class = target.first.class
|
37
37
|
if association_class.query_constraints_list
|
38
|
-
primary_key_column = association_class.query_constraints_list
|
38
|
+
primary_key_column = association_class.query_constraints_list
|
39
39
|
ids = target.collect { |assoc| primary_key_column.map { |col| assoc.public_send(col) } }
|
40
40
|
else
|
41
|
-
primary_key_column = association_class.primary_key
|
41
|
+
primary_key_column = association_class.primary_key
|
42
42
|
ids = target.collect { |assoc| assoc.public_send(primary_key_column) }
|
43
43
|
end
|
44
44
|
|
@@ -34,10 +34,10 @@ module ActiveRecord
|
|
34
34
|
throw(:abort) unless target.destroyed?
|
35
35
|
when :destroy_async
|
36
36
|
if target.class.query_constraints_list
|
37
|
-
primary_key_column = target.class.query_constraints_list
|
37
|
+
primary_key_column = target.class.query_constraints_list
|
38
38
|
id = primary_key_column.map { |col| target.public_send(col) }
|
39
39
|
else
|
40
|
-
primary_key_column = target.class.primary_key
|
40
|
+
primary_key_column = target.class.primary_key
|
41
41
|
id = target.public_send(primary_key_column)
|
42
42
|
end
|
43
43
|
|
@@ -25,8 +25,9 @@ module ActiveRecord
|
|
25
25
|
joins = []
|
26
26
|
chain = []
|
27
27
|
|
28
|
-
reflection.chain
|
29
|
-
|
28
|
+
reflection_chain = reflection.chain
|
29
|
+
reflection_chain.each_with_index do |reflection, index|
|
30
|
+
table, terminated = yield reflection, reflection_chain[index..]
|
30
31
|
@table ||= table
|
31
32
|
|
32
33
|
if terminated
|
@@ -61,7 +61,7 @@ module ActiveRecord
|
|
61
61
|
when Hash
|
62
62
|
associations.each do |k, v|
|
63
63
|
cache = hash[k] ||= {}
|
64
|
-
walk_tree v, cache
|
64
|
+
walk_tree v, cache if v
|
65
65
|
end
|
66
66
|
else
|
67
67
|
raise ConfigurationError, associations.inspect
|
@@ -190,12 +190,12 @@ module ActiveRecord
|
|
190
190
|
def make_constraints(parent, child, join_type)
|
191
191
|
foreign_table = parent.table
|
192
192
|
foreign_klass = parent.base_klass
|
193
|
-
child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) do |reflection|
|
194
|
-
table, terminated = @joined_tables[
|
193
|
+
child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) do |reflection, remaining_reflection_chain|
|
194
|
+
table, terminated = @joined_tables[remaining_reflection_chain]
|
195
195
|
root = reflection == child.reflection
|
196
196
|
|
197
197
|
if table && (!root || !terminated)
|
198
|
-
@joined_tables[
|
198
|
+
@joined_tables[remaining_reflection_chain] = [table, root] if root
|
199
199
|
next table, true
|
200
200
|
end
|
201
201
|
|
@@ -206,7 +206,7 @@ module ActiveRecord
|
|
206
206
|
root ? name : "#{name}_join"
|
207
207
|
end
|
208
208
|
|
209
|
-
@joined_tables[
|
209
|
+
@joined_tables[remaining_reflection_chain] ||= [table, root] if join_type == Arel::Nodes::OuterJoin
|
210
210
|
table
|
211
211
|
end.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
212
212
|
end
|
@@ -254,10 +254,10 @@ module ActiveRecord
|
|
254
254
|
|
255
255
|
if node.primary_key
|
256
256
|
keys = Array(node.primary_key).map { |column| aliases.column_alias(node, column) }
|
257
|
-
|
257
|
+
id = keys.map { |key| row[key] }
|
258
258
|
else
|
259
259
|
keys = Array(node.reflection.join_primary_key).map { |column| aliases.column_alias(node, column.to_s) }
|
260
|
-
|
260
|
+
id = keys.map { nil } # Avoid id-based model caching.
|
261
261
|
end
|
262
262
|
|
263
263
|
if keys.any? { |key| row[key].nil? }
|
@@ -266,11 +266,9 @@ module ActiveRecord
|
|
266
266
|
next
|
267
267
|
end
|
268
268
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
seen[ar_parent][node][id] = model if id
|
273
|
-
end
|
269
|
+
unless model = seen[ar_parent][node][id]
|
270
|
+
model = construct_model(ar_parent, node, row, model_cache, id, strict_loading_value)
|
271
|
+
seen[ar_parent][node][id] = model if id
|
274
272
|
end
|
275
273
|
|
276
274
|
construct(model, node, row, seen, model_cache, strict_loading_value)
|
@@ -1506,6 +1506,11 @@ module ActiveRecord
|
|
1506
1506
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
1507
1507
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
1508
1508
|
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
1509
|
+
# [+:index_errors+]
|
1510
|
+
# Enables differentiation of multiple validation errors from the association records, by including
|
1511
|
+
# 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
|
1513
|
+
# persisted new records placed at the end.
|
1509
1514
|
#
|
1510
1515
|
# Option examples:
|
1511
1516
|
# has_many :comments, -> { order("posted_on") }
|
@@ -1519,6 +1524,7 @@ module ActiveRecord
|
|
1519
1524
|
# has_many :subscribers, through: :subscriptions, disable_joins: true
|
1520
1525
|
# has_many :comments, strict_loading: true
|
1521
1526
|
# has_many :comments, query_constraints: [:blog_id, :post_id]
|
1527
|
+
# has_many :comments, index_errors: true
|
1522
1528
|
def has_many(name, scope = nil, **options, &extension)
|
1523
1529
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
1524
1530
|
Reflection.add_reflection self, name, reflection
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
# person.name_in_database # => "Alice"
|
32
32
|
# person.saved_change_to_name? # => true
|
33
33
|
# person.saved_change_to_name # => ["Allison", "Alice"]
|
34
|
-
# person.
|
34
|
+
# person.name_before_last_save # => "Allison"
|
35
35
|
#
|
36
36
|
# Similar to ActiveModel::Dirty, methods can be invoked as
|
37
37
|
# +saved_change_to_name?+ or by passing an argument to the generic method
|
@@ -251,7 +251,7 @@ module ActiveRecord
|
|
251
251
|
changed_attribute_names_to_save
|
252
252
|
else
|
253
253
|
attribute_names.reject do |attr_name|
|
254
|
-
if column_for_attribute(attr_name).
|
254
|
+
if column_for_attribute(attr_name).auto_populated?
|
255
255
|
!attribute_changed?(attr_name)
|
256
256
|
end
|
257
257
|
end
|
@@ -8,11 +8,11 @@ module ActiveRecord
|
|
8
8
|
|
9
9
|
module ClassMethods # :nodoc:
|
10
10
|
private
|
11
|
-
def define_method_attribute(
|
11
|
+
def define_method_attribute(canonical_name, owner:, as: canonical_name)
|
12
12
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
13
|
-
owner,
|
13
|
+
owner, canonical_name
|
14
14
|
) do |temp_method_name, attr_name_expr|
|
15
|
-
owner.define_cached_method(
|
15
|
+
owner.define_cached_method(temp_method_name, as: as, namespace: :active_record) do |batch|
|
16
16
|
batch <<
|
17
17
|
"def #{temp_method_name}" <<
|
18
18
|
" _read_attribute(#{attr_name_expr}) { |n| missing_attribute(n, caller) }" <<
|
@@ -12,11 +12,11 @@ module ActiveRecord
|
|
12
12
|
|
13
13
|
module ClassMethods # :nodoc:
|
14
14
|
private
|
15
|
-
def define_method_attribute=(
|
15
|
+
def define_method_attribute=(canonical_name, owner:, as: canonical_name)
|
16
16
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
17
|
-
owner,
|
17
|
+
owner, canonical_name, writer: true,
|
18
18
|
) do |temp_method_name, attr_name_expr|
|
19
|
-
owner.define_cached_method("#{
|
19
|
+
owner.define_cached_method(temp_method_name, as: "#{as}=", namespace: :active_record) do |batch|
|
20
20
|
batch <<
|
21
21
|
"def #{temp_method_name}(value)" <<
|
22
22
|
" _write_attribute(#{attr_name_expr}, value)" <<
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
|
67
67
|
def generate_alias_attributes # :nodoc:
|
68
68
|
superclass.generate_alias_attributes unless superclass == Base
|
69
|
-
return if @alias_attributes_mass_generated
|
69
|
+
return false if @alias_attributes_mass_generated
|
70
70
|
|
71
71
|
generated_attribute_methods.synchronize do
|
72
72
|
return if @alias_attributes_mass_generated
|
@@ -80,12 +80,19 @@ module ActiveRecord
|
|
80
80
|
|
81
81
|
@alias_attributes_mass_generated = true
|
82
82
|
end
|
83
|
+
true
|
83
84
|
end
|
84
85
|
|
85
|
-
def
|
86
|
+
def generate_alias_attribute_methods(code_generator, new_name, old_name) # :nodoc:
|
87
|
+
attribute_method_patterns.each do |pattern|
|
88
|
+
alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
|
89
|
+
end
|
90
|
+
attribute_method_patterns_cache.clear
|
91
|
+
end
|
92
|
+
|
93
|
+
def alias_attribute_method_definition(code_generator, pattern, new_name, old_name) # :nodoc:
|
86
94
|
method_name = pattern.method_name(new_name).to_s
|
87
95
|
target_name = pattern.method_name(old_name).to_s
|
88
|
-
parameters = pattern.parameters
|
89
96
|
old_name = old_name.to_s
|
90
97
|
|
91
98
|
method_defined = method_defined?(target_name) || private_method_defined?(target_name)
|
@@ -115,9 +122,7 @@ module ActiveRecord
|
|
115
122
|
)
|
116
123
|
super
|
117
124
|
else
|
118
|
-
|
119
|
-
namespace: :proxy_alias_attribute
|
120
|
-
)
|
125
|
+
define_attribute_method_pattern(pattern, old_name, owner: code_generator, as: new_name, override: true)
|
121
126
|
end
|
122
127
|
end
|
123
128
|
|
@@ -133,6 +138,11 @@ module ActiveRecord
|
|
133
138
|
super(attribute_names)
|
134
139
|
@attribute_methods_generated = true
|
135
140
|
end
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
def attribute_methods_generated? # :nodoc:
|
145
|
+
@attribute_methods_generated && @alias_attributes_mass_generated
|
136
146
|
end
|
137
147
|
|
138
148
|
def undefine_attribute_methods # :nodoc:
|
@@ -459,6 +469,36 @@ module ActiveRecord
|
|
459
469
|
end
|
460
470
|
|
461
471
|
private
|
472
|
+
def respond_to_missing?(name, include_private = false)
|
473
|
+
if self.class.define_attribute_methods
|
474
|
+
# Some methods weren't defined yet.
|
475
|
+
return true if self.class.method_defined?(name)
|
476
|
+
return true if include_private && self.class.private_method_defined?(name)
|
477
|
+
end
|
478
|
+
|
479
|
+
super
|
480
|
+
end
|
481
|
+
|
482
|
+
def method_missing(name, ...)
|
483
|
+
unless self.class.attribute_methods_generated?
|
484
|
+
if self.class.method_defined?(name)
|
485
|
+
# The method is explicitly defined in the model, but calls a generated
|
486
|
+
# method with super. So we must resume the call chain at the right setp.
|
487
|
+
last_method = method(name)
|
488
|
+
last_method = last_method.super_method while last_method.super_method
|
489
|
+
self.class.define_attribute_methods
|
490
|
+
if last_method.super_method
|
491
|
+
return last_method.super_method.call(...)
|
492
|
+
end
|
493
|
+
elsif self.class.define_attribute_methods | self.class.generate_alias_attributes
|
494
|
+
# Some attribute methods weren't generated yet, we retry the call
|
495
|
+
return public_send(name, ...)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
super
|
500
|
+
end
|
501
|
+
|
462
502
|
def attribute_method?(attr_name)
|
463
503
|
# We check defined? because Syck calls respond_to? before actually calling initialize.
|
464
504
|
defined?(@attributes) && @attributes.key?(attr_name)
|
@@ -441,7 +441,9 @@ module ActiveRecord
|
|
441
441
|
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
|
442
442
|
def save_has_one_association(reflection)
|
443
443
|
association = association_instance_get(reflection.name)
|
444
|
-
|
444
|
+
return unless association && association.loaded?
|
445
|
+
|
446
|
+
record = association.load_target
|
445
447
|
|
446
448
|
if record && !record.destroyed?
|
447
449
|
autosave = reflection.options[:autosave]
|
@@ -458,7 +460,8 @@ module ActiveRecord
|
|
458
460
|
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
459
461
|
|
460
462
|
primary_key_foreign_key_pairs.each do |primary_key, foreign_key|
|
461
|
-
|
463
|
+
association_id = _read_attribute(primary_key)
|
464
|
+
record[foreign_key] = association_id unless record[foreign_key] == association_id
|
462
465
|
end
|
463
466
|
association.set_inverse_instance(record)
|
464
467
|
end
|