activerecord 5.2.0 → 5.2.8.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +361 -0
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +25 -10
- data/lib/active_record/associations/belongs_to_association.rb +14 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
- data/lib/active_record/associations/builder/belongs_to.rb +11 -2
- data/lib/active_record/associations/builder/collection_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +19 -15
- data/lib/active_record/associations/collection_proxy.rb +8 -34
- data/lib/active_record/associations/has_many_association.rb +9 -0
- data/lib/active_record/associations/has_many_through_association.rb +29 -12
- data/lib/active_record/associations/has_one_association.rb +8 -0
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -24
- data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
- data/lib/active_record/associations/join_dependency.rb +39 -64
- data/lib/active_record/associations/preloader.rb +1 -1
- data/lib/active_record/associations/singular_association.rb +4 -10
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +9 -9
- data/lib/active_record/attribute_methods/dirty.rb +15 -10
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/autosave_association.rb +27 -8
- data/lib/active_record/callbacks.rb +4 -0
- data/lib/active_record/coders/yaml_column.rb +13 -1
- data/lib/active_record/collection_cache_key.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +36 -11
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +19 -6
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +6 -15
- data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
- data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -19
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -6
- data/lib/active_record/core.rb +12 -1
- data/lib/active_record/counter_cache.rb +17 -13
- data/lib/active_record/enum.rb +1 -0
- data/lib/active_record/errors.rb +18 -12
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration/compatibility.rb +15 -15
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/persistence.rb +6 -5
- data/lib/active_record/query_cache.rb +4 -11
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +19 -3
- data/lib/active_record/reflection.rb +10 -14
- data/lib/active_record/relation/calculations.rb +16 -12
- data/lib/active_record/relation/delegation.rb +30 -0
- data/lib/active_record/relation/finder_methods.rb +10 -8
- data/lib/active_record/relation/merger.rb +10 -11
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder.rb +20 -14
- data/lib/active_record/relation/query_attribute.rb +5 -3
- data/lib/active_record/relation/query_methods.rb +50 -22
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation.rb +39 -20
- data/lib/active_record/scoping/default.rb +2 -2
- data/lib/active_record/scoping/named.rb +2 -0
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +1 -1
- data/lib/active_record/timestamp.rb +8 -1
- data/lib/active_record/transactions.rb +24 -21
- data/lib/active_record/type/serialized.rb +4 -0
- metadata +12 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86737eb3187422c20dfc6d14b175ae9d541dfe670178da64a024c0968693ef81
|
4
|
+
data.tar.gz: 767900fd0d4a68dae1536cb7750e5456bc2bac72fde2ce7518ff69b1e5c8c706
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0af8b7124c2d152f219220f518615b135137bb610d747b520d9c28370c73c966110121c3bede44a3ca0b9c36a4650f7ed300548e658eda7c888f7298b2f45162
|
7
|
+
data.tar.gz: 1a72afb896390c797673d4a100d7d9abd055a63fea21cef26e896a0cb424a64de661e99abb8cd80347643720d5c529dabe92af619dcaa7ff8610f4b3c1782483
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,364 @@
|
|
1
|
+
## Rails 5.2.8.1 (July 12, 2022) ##
|
2
|
+
|
3
|
+
* Change ActiveRecord::Coders::YAMLColumn default to safe_load
|
4
|
+
|
5
|
+
This adds two new configuration options The configuration options are as
|
6
|
+
follows:
|
7
|
+
|
8
|
+
* `config.active_storage.use_yaml_unsafe_load`
|
9
|
+
|
10
|
+
When set to true, this configuration option tells Rails to use the old
|
11
|
+
"unsafe" YAML loading strategy, maintaining the existing behavior but leaving
|
12
|
+
the possible escalation vulnerability in place. Setting this option to true
|
13
|
+
is *not* recommended, but can aid in upgrading.
|
14
|
+
|
15
|
+
* `config.active_record.yaml_column_permitted_classes`
|
16
|
+
|
17
|
+
The "safe YAML" loading method does not allow all classes to be deserialized
|
18
|
+
by default. This option allows you to specify classes deemed "safe" in your
|
19
|
+
application. For example, if your application uses Symbol and Time in
|
20
|
+
serialized data, you can add Symbol and Time to the allowed list as follows:
|
21
|
+
|
22
|
+
```
|
23
|
+
config.active_record.yaml_column_permitted_classes = [Symbol, Date, Time]
|
24
|
+
```
|
25
|
+
|
26
|
+
[CVE-2022-32224]
|
27
|
+
|
28
|
+
|
29
|
+
## Rails 5.2.8 (May 09, 2022) ##
|
30
|
+
|
31
|
+
* No changes.
|
32
|
+
|
33
|
+
|
34
|
+
## Rails 5.2.7.1 (April 26, 2022) ##
|
35
|
+
|
36
|
+
* No changes.
|
37
|
+
|
38
|
+
|
39
|
+
## Rails 5.2.7 (March 10, 2022) ##
|
40
|
+
|
41
|
+
* No changes.
|
42
|
+
|
43
|
+
|
44
|
+
## Rails 5.2.6.3 (March 08, 2022) ##
|
45
|
+
|
46
|
+
* No changes.
|
47
|
+
|
48
|
+
|
49
|
+
## Rails 5.2.6.2 (February 11, 2022) ##
|
50
|
+
|
51
|
+
* No changes.
|
52
|
+
|
53
|
+
|
54
|
+
## Rails 5.2.6.1 (February 11, 2022) ##
|
55
|
+
|
56
|
+
* No changes.
|
57
|
+
|
58
|
+
|
59
|
+
## Rails 5.2.6 (May 05, 2021) ##
|
60
|
+
|
61
|
+
* No changes.
|
62
|
+
|
63
|
+
|
64
|
+
## Rails 5.2.5 (March 26, 2021) ##
|
65
|
+
|
66
|
+
* No changes.
|
67
|
+
|
68
|
+
|
69
|
+
## Rails 5.2.4.6 (May 05, 2021) ##
|
70
|
+
|
71
|
+
* No changes.
|
72
|
+
|
73
|
+
|
74
|
+
## Rails 5.2.4.5 (February 10, 2021) ##
|
75
|
+
|
76
|
+
* Fix possible DoS vector in PostgreSQL money type
|
77
|
+
|
78
|
+
Carefully crafted input can cause a DoS via the regular expressions used
|
79
|
+
for validating the money format in the PostgreSQL adapter. This patch
|
80
|
+
fixes the regexp.
|
81
|
+
|
82
|
+
Thanks to @dee-see from Hackerone for this patch!
|
83
|
+
|
84
|
+
[CVE-2021-22880]
|
85
|
+
|
86
|
+
*Aaron Patterson*
|
87
|
+
|
88
|
+
|
89
|
+
## Rails 5.2.4.4 (September 09, 2020) ##
|
90
|
+
|
91
|
+
* No changes.
|
92
|
+
|
93
|
+
|
94
|
+
## Rails 5.2.4.3 (May 18, 2020) ##
|
95
|
+
|
96
|
+
* No changes.
|
97
|
+
|
98
|
+
## Rails 5.2.4.2 (March 19, 2020) ##
|
99
|
+
|
100
|
+
* No changes.
|
101
|
+
|
102
|
+
|
103
|
+
## Rails 5.2.4.1 (December 18, 2019) ##
|
104
|
+
|
105
|
+
* No changes.
|
106
|
+
|
107
|
+
|
108
|
+
## Rails 5.2.4 (November 27, 2019) ##
|
109
|
+
|
110
|
+
* Fix circular `autosave: true` causes invalid records to be saved.
|
111
|
+
|
112
|
+
Prior to the fix, when there was a circular series of `autosave: true`
|
113
|
+
associations, the callback for a `has_many` association was run while
|
114
|
+
another instance of the same callback on the same association hadn't
|
115
|
+
finished running. When control returned to the first instance of the
|
116
|
+
callback, the instance variable had changed, and subsequent associated
|
117
|
+
records weren't saved correctly. Specifically, the ID field for the
|
118
|
+
`belongs_to` corresponding to the `has_many` was `nil`.
|
119
|
+
|
120
|
+
Fixes #28080.
|
121
|
+
|
122
|
+
*Larry Reid*
|
123
|
+
|
124
|
+
* PostgreSQL: Fix GROUP BY with ORDER BY virtual count attribute.
|
125
|
+
|
126
|
+
Fixes #36022.
|
127
|
+
|
128
|
+
*Ryuta Kamizono*
|
129
|
+
|
130
|
+
* Fix sqlite3 collation parsing when using decimal columns.
|
131
|
+
|
132
|
+
*Martin R. Schuster*
|
133
|
+
|
134
|
+
* Make ActiveRecord `ConnectionPool.connections` method thread-safe.
|
135
|
+
|
136
|
+
Fixes #36465.
|
137
|
+
|
138
|
+
*Jeff Doering*
|
139
|
+
|
140
|
+
* Assign all attributes before calling `build` to ensure the child record is visible in
|
141
|
+
`before_add` and `after_add` callbacks for `has_many :through` associations.
|
142
|
+
|
143
|
+
Fixes #33249.
|
144
|
+
|
145
|
+
*Ryan H. Kerr*
|
146
|
+
|
147
|
+
|
148
|
+
## Rails 5.2.3 (March 27, 2019) ##
|
149
|
+
|
150
|
+
* Fix different `count` calculation when using `size` with manual `select` with DISTINCT.
|
151
|
+
|
152
|
+
Fixes #35214.
|
153
|
+
|
154
|
+
*Juani Villarejo*
|
155
|
+
|
156
|
+
* Fix prepared statements caching to be enabled even when query caching is enabled.
|
157
|
+
|
158
|
+
*Ryuta Kamizono*
|
159
|
+
|
160
|
+
* Don't allow `where` with invalid value matches to nil values.
|
161
|
+
|
162
|
+
Fixes #33624.
|
163
|
+
|
164
|
+
*Ryuta Kamizono*
|
165
|
+
|
166
|
+
* Restore an ability that class level `update` without giving ids.
|
167
|
+
|
168
|
+
Fixes #34743.
|
169
|
+
|
170
|
+
*Ryuta Kamizono*
|
171
|
+
|
172
|
+
* Fix join table column quoting with SQLite.
|
173
|
+
|
174
|
+
*Gannon McGibbon*
|
175
|
+
|
176
|
+
* Ensure that `delete_all` on collection proxy returns affected count.
|
177
|
+
|
178
|
+
*Ryuta Kamizono*
|
179
|
+
|
180
|
+
* Reset scope after delete on collection association to clear stale offsets of removed records.
|
181
|
+
|
182
|
+
*Gannon McGibbon*
|
183
|
+
|
184
|
+
|
185
|
+
## Rails 5.2.2.1 (March 11, 2019) ##
|
186
|
+
|
187
|
+
* No changes.
|
188
|
+
|
189
|
+
|
190
|
+
## Rails 5.2.2 (December 04, 2018) ##
|
191
|
+
|
192
|
+
* Do not ignore the scoping with query methods in the scope block.
|
193
|
+
|
194
|
+
*Ryuta Kamizono*
|
195
|
+
|
196
|
+
* Allow aliased attributes to be used in `#update_columns` and `#update`.
|
197
|
+
|
198
|
+
*Gannon McGibbon*
|
199
|
+
|
200
|
+
* Allow spaces in postgres table names.
|
201
|
+
|
202
|
+
Fixes issue where "user post" is misinterpreted as "\"user\".\"post\"" when quoting table names with the postgres
|
203
|
+
adapter.
|
204
|
+
|
205
|
+
*Gannon McGibbon*
|
206
|
+
|
207
|
+
* Cached columns_hash fields should be excluded from ResultSet#column_types
|
208
|
+
|
209
|
+
PR #34528 addresses the inconsistent behaviour when attribute is defined for an ignored column. The following test
|
210
|
+
was passing for SQLite and MySQL, but failed for PostgreSQL:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
class DeveloperName < ActiveRecord::Type::String
|
214
|
+
def deserialize(value)
|
215
|
+
"Developer: #{value}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class AttributedDeveloper < ActiveRecord::Base
|
220
|
+
self.table_name = "developers"
|
221
|
+
|
222
|
+
attribute :name, DeveloperName.new
|
223
|
+
|
224
|
+
self.ignored_columns += ["name"]
|
225
|
+
end
|
226
|
+
|
227
|
+
developer = AttributedDeveloper.create
|
228
|
+
developer.update_column :name, "name"
|
229
|
+
|
230
|
+
loaded_developer = AttributedDeveloper.where(id: developer.id).select("*").first
|
231
|
+
puts loaded_developer.name # should be "Developer: name" but it's just "name"
|
232
|
+
```
|
233
|
+
|
234
|
+
*Dmitry Tsepelev*
|
235
|
+
|
236
|
+
* Values of enum are frozen, raising an error when attempting to modify them.
|
237
|
+
|
238
|
+
*Emmanuel Byrd*
|
239
|
+
|
240
|
+
* `update_columns` now correctly raises `ActiveModel::MissingAttributeError`
|
241
|
+
if the attribute does not exist.
|
242
|
+
|
243
|
+
*Sean Griffin*
|
244
|
+
|
245
|
+
* Do not use prepared statement in queries that have a large number of binds.
|
246
|
+
|
247
|
+
*Ryuta Kamizono*
|
248
|
+
|
249
|
+
* Fix query cache to load before first request.
|
250
|
+
|
251
|
+
*Eileen M. Uchitelle*
|
252
|
+
|
253
|
+
* Fix collection cache key with limit and custom select to avoid ambiguous timestamp column error.
|
254
|
+
|
255
|
+
Fixes #33056.
|
256
|
+
|
257
|
+
*Federico Martinez*
|
258
|
+
|
259
|
+
* Fix duplicated record creation when using nested attributes with `create_with`.
|
260
|
+
|
261
|
+
*Darwin Wu*
|
262
|
+
|
263
|
+
* Fix regression setting children record in parent `before_save` callback.
|
264
|
+
|
265
|
+
*Guo Xiang Tan*
|
266
|
+
|
267
|
+
* Prevent leaking of user's DB credentials on `rails db:create` failure.
|
268
|
+
|
269
|
+
*bogdanvlviv*
|
270
|
+
|
271
|
+
* Clear mutation tracker before continuing the around callbacks.
|
272
|
+
|
273
|
+
*Yuya Tanaka*
|
274
|
+
|
275
|
+
* Prevent deadlocks when waiting for connection from pool.
|
276
|
+
|
277
|
+
*Brent Wheeldon*
|
278
|
+
|
279
|
+
* Avoid extra scoping when using `Relation#update` that was causing this method to change the current scope.
|
280
|
+
|
281
|
+
*Ryuta Kamizono*
|
282
|
+
|
283
|
+
* Fix numericality validator not to be affected by custom getter.
|
284
|
+
|
285
|
+
*Ryuta Kamizono*
|
286
|
+
|
287
|
+
* Fix bulk change table ignores comment option on PostgreSQL.
|
288
|
+
|
289
|
+
*Yoshiyuki Kinjo*
|
290
|
+
|
291
|
+
|
292
|
+
## Rails 5.2.1.1 (November 27, 2018) ##
|
293
|
+
|
294
|
+
* No changes.
|
295
|
+
|
296
|
+
|
297
|
+
## Rails 5.2.1 (August 07, 2018) ##
|
298
|
+
|
299
|
+
* PostgreSQL: Support new relkind for partitioned tables.
|
300
|
+
|
301
|
+
Fixes #33008.
|
302
|
+
|
303
|
+
*Yannick Schutz*
|
304
|
+
|
305
|
+
* Rollback parent transaction when children fails to update.
|
306
|
+
|
307
|
+
*Guillaume Malette*
|
308
|
+
|
309
|
+
* Fix default value for MySQL time types with specified precision.
|
310
|
+
|
311
|
+
*Nikolay Kondratyev*
|
312
|
+
|
313
|
+
* Fix `touch` option to behave consistently with `Persistence#touch` method.
|
314
|
+
|
315
|
+
*Ryuta Kamizono*
|
316
|
+
|
317
|
+
* Fix `save` in `after_create_commit` won't invoke extra `after_create_commit`.
|
318
|
+
|
319
|
+
Fixes #32831.
|
320
|
+
|
321
|
+
*Ryuta Kamizono*
|
322
|
+
|
323
|
+
* Fix logic on disabling commit callbacks so they are not called unexpectedly when errors occur.
|
324
|
+
|
325
|
+
*Brian Durand*
|
326
|
+
|
327
|
+
* Fix parent record should not get saved with duplicate children records.
|
328
|
+
|
329
|
+
Fixes #32940.
|
330
|
+
|
331
|
+
*Santosh Wadghule*
|
332
|
+
|
333
|
+
* Fix that association's after_touch is not called with counter cache.
|
334
|
+
|
335
|
+
Fixes #31559.
|
336
|
+
|
337
|
+
*Ryuta Kamizono*
|
338
|
+
|
339
|
+
* `becomes` should clear the mutation tracker which is created in `after_initialize`.
|
340
|
+
|
341
|
+
Fixes #32867.
|
342
|
+
|
343
|
+
*Ryuta Kamizono*
|
344
|
+
|
345
|
+
* Allow a belonging to parent object to be created from a new record.
|
346
|
+
|
347
|
+
*Jolyon Pawlyn*
|
348
|
+
|
349
|
+
* Fix that building record with assigning multiple has_one associations
|
350
|
+
wrongly persists through record.
|
351
|
+
|
352
|
+
Fixes #32511.
|
353
|
+
|
354
|
+
*Sam DeCesare*
|
355
|
+
|
356
|
+
* Fix relation merging when one of the relations is going to skip the
|
357
|
+
query cache.
|
358
|
+
|
359
|
+
*James Williams*
|
360
|
+
|
361
|
+
|
1
362
|
## Rails 5.2.0 (April 09, 2018) ##
|
2
363
|
|
3
364
|
* MySQL: Support mysql2 0.5.x.
|
@@ -31,9 +31,9 @@ module ActiveRecord
|
|
31
31
|
private
|
32
32
|
|
33
33
|
def exec_queries
|
34
|
-
super do |
|
35
|
-
@association.
|
36
|
-
yield
|
34
|
+
super do |record|
|
35
|
+
@association.set_inverse_instance_from_queries(record)
|
36
|
+
yield record if block_given?
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -19,7 +19,6 @@ module ActiveRecord
|
|
19
19
|
# HasManyThroughAssociation + ThroughAssociation
|
20
20
|
class Association #:nodoc:
|
21
21
|
attr_reader :owner, :target, :reflection
|
22
|
-
attr_accessor :inversed
|
23
22
|
|
24
23
|
delegate :options, to: :reflection
|
25
24
|
|
@@ -67,7 +66,7 @@ module ActiveRecord
|
|
67
66
|
#
|
68
67
|
# Note that if the target has not been loaded, it is not considered stale.
|
69
68
|
def stale_target?
|
70
|
-
|
69
|
+
!@inversed && loaded? && @stale_state != stale_state
|
71
70
|
end
|
72
71
|
|
73
72
|
# Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
|
@@ -98,23 +97,32 @@ module ActiveRecord
|
|
98
97
|
|
99
98
|
# Set the inverse association, if possible
|
100
99
|
def set_inverse_instance(record)
|
101
|
-
if
|
102
|
-
inverse
|
103
|
-
|
104
|
-
|
100
|
+
if inverse = inverse_association_for(record)
|
101
|
+
inverse.inversed_from(owner)
|
102
|
+
end
|
103
|
+
record
|
104
|
+
end
|
105
|
+
|
106
|
+
def set_inverse_instance_from_queries(record)
|
107
|
+
if inverse = inverse_association_for(record)
|
108
|
+
inverse.inversed_from_queries(owner)
|
105
109
|
end
|
106
110
|
record
|
107
111
|
end
|
108
112
|
|
109
113
|
# Remove the inverse association, if possible
|
110
114
|
def remove_inverse_instance(record)
|
111
|
-
if
|
112
|
-
inverse
|
113
|
-
inverse.target = nil
|
114
|
-
inverse.inversed = false
|
115
|
+
if inverse = inverse_association_for(record)
|
116
|
+
inverse.inversed_from(nil)
|
115
117
|
end
|
116
118
|
end
|
117
119
|
|
120
|
+
def inversed_from(record)
|
121
|
+
self.target = record
|
122
|
+
@inversed = !!record
|
123
|
+
end
|
124
|
+
alias :inversed_from_queries :inversed_from
|
125
|
+
|
118
126
|
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
|
119
127
|
# polymorphic_type field on the owner.
|
120
128
|
def klass
|
@@ -240,6 +248,12 @@ module ActiveRecord
|
|
240
248
|
end
|
241
249
|
end
|
242
250
|
|
251
|
+
def inverse_association_for(record)
|
252
|
+
if invertible_for?(record)
|
253
|
+
record.association(inverse_reflection_for(record).name)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
243
257
|
# Can be redefined by subclasses, notably polymorphic belongs_to
|
244
258
|
# The record parameter is necessary to support polymorphic inverses as we must check for
|
245
259
|
# the association in the specific class of the record.
|
@@ -269,6 +283,7 @@ module ActiveRecord
|
|
269
283
|
def build_record(attributes)
|
270
284
|
reflection.build_association(attributes) do |record|
|
271
285
|
initialize_attributes(record, attributes)
|
286
|
+
yield(record) if block_given?
|
272
287
|
end
|
273
288
|
end
|
274
289
|
|
@@ -26,10 +26,12 @@ module ActiveRecord
|
|
26
26
|
decrement_counters
|
27
27
|
end
|
28
28
|
|
29
|
+
replace_keys(record)
|
30
|
+
|
29
31
|
self.target = record
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
34
|
+
def inversed_from(record)
|
33
35
|
replace_keys(record)
|
34
36
|
super
|
35
37
|
end
|
@@ -55,6 +57,10 @@ module ActiveRecord
|
|
55
57
|
update_counters(1)
|
56
58
|
end
|
57
59
|
|
60
|
+
def target_changed?
|
61
|
+
owner.saved_change_to_attribute?(reflection.foreign_key)
|
62
|
+
end
|
63
|
+
|
58
64
|
private
|
59
65
|
|
60
66
|
def update_counters(by)
|
@@ -78,19 +84,22 @@ module ActiveRecord
|
|
78
84
|
def update_counters_on_replace(record)
|
79
85
|
if require_counter_update? && different_target?(record)
|
80
86
|
owner.instance_variable_set :@_after_replace_counter_called, true
|
81
|
-
record.increment!(reflection.counter_cache_column)
|
87
|
+
record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
|
82
88
|
decrement_counters
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
86
92
|
# Checks whether record is different to the current target, without loading it
|
87
93
|
def different_target?(record)
|
88
|
-
record.
|
94
|
+
record._read_attribute(primary_key(record)) != owner._read_attribute(reflection.foreign_key)
|
89
95
|
end
|
90
96
|
|
91
97
|
def replace_keys(record)
|
92
|
-
owner[reflection.foreign_key] = record ?
|
93
|
-
|
98
|
+
owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def primary_key(record)
|
102
|
+
reflection.association_primary_key(record.class)
|
94
103
|
end
|
95
104
|
|
96
105
|
def foreign_key_present?
|
@@ -9,8 +9,11 @@ module ActiveRecord
|
|
9
9
|
type.presence && type.constantize
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
def target_changed?
|
13
|
+
super || owner.saved_change_to_attribute?(reflection.foreign_type)
|
14
|
+
end
|
13
15
|
|
16
|
+
private
|
14
17
|
def replace_keys(record)
|
15
18
|
super
|
16
19
|
owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
|
@@ -36,7 +36,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
36
36
|
|
37
37
|
if (@_after_replace_counter_called ||= false)
|
38
38
|
@_after_replace_counter_called = false
|
39
|
-
elsif
|
39
|
+
elsif association(reflection.name).target_changed?
|
40
40
|
if reflection.polymorphic?
|
41
41
|
model = attribute_in_database(reflection.foreign_type).try(:constantize)
|
42
42
|
model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
|
@@ -49,14 +49,22 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
49
49
|
foreign_key = attribute_in_database foreign_key
|
50
50
|
|
51
51
|
if foreign_key && model.respond_to?(:increment_counter)
|
52
|
+
foreign_key = counter_cache_target(reflection, model, foreign_key)
|
52
53
|
model.increment_counter(cache_column, foreign_key)
|
53
54
|
end
|
54
55
|
|
55
56
|
if foreign_key_was && model_was.respond_to?(:decrement_counter)
|
57
|
+
foreign_key_was = counter_cache_target(reflection, model_was, foreign_key_was)
|
56
58
|
model_was.decrement_counter(cache_column, foreign_key_was)
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def counter_cache_target(reflection, model, foreign_key)
|
65
|
+
primary_key = reflection.association_primary_key(model)
|
66
|
+
model.unscoped.where!(primary_key => foreign_key)
|
67
|
+
end
|
60
68
|
end
|
61
69
|
end
|
62
70
|
|
@@ -84,7 +92,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
84
92
|
else
|
85
93
|
klass = association.klass
|
86
94
|
end
|
87
|
-
|
95
|
+
primary_key = reflection.association_primary_key(klass)
|
96
|
+
old_record = klass.find_by(primary_key => old_foreign_id)
|
88
97
|
|
89
98
|
if old_record
|
90
99
|
if touch != true
|
@@ -20,10 +20,10 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.define_extensions(model, name)
|
23
|
+
def self.define_extensions(model, name, &block)
|
24
24
|
if block_given?
|
25
25
|
extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
|
26
|
-
extension = Module.new(&
|
26
|
+
extension = Module.new(&block)
|
27
27
|
model.parent.const_set(extension_module_name, extension)
|
28
28
|
end
|
29
29
|
end
|
@@ -45,6 +45,8 @@ module ActiveRecord
|
|
45
45
|
def ids_reader
|
46
46
|
if loaded?
|
47
47
|
target.pluck(reflection.association_primary_key)
|
48
|
+
elsif !target.empty?
|
49
|
+
load_target.pluck(reflection.association_primary_key)
|
48
50
|
else
|
49
51
|
@association_ids ||= scope.pluck(reflection.association_primary_key)
|
50
52
|
end
|
@@ -103,15 +105,12 @@ module ActiveRecord
|
|
103
105
|
if attributes.is_a?(Array)
|
104
106
|
attributes.collect { |attr| build(attr, &block) }
|
105
107
|
else
|
106
|
-
add_to_target(build_record(attributes))
|
107
|
-
yield(record) if block_given?
|
108
|
-
end
|
108
|
+
add_to_target(build_record(attributes, &block))
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
-
# Add +records+ to this association.
|
113
|
-
#
|
114
|
-
# +push+ and +concat+ behave identically.
|
112
|
+
# Add +records+ to this association. Since +<<+ flattens its argument list
|
113
|
+
# and inserts each record, +push+ and +concat+ behave identically.
|
115
114
|
def concat(*records)
|
116
115
|
records = records.flatten
|
117
116
|
if owner.new_record?
|
@@ -356,15 +355,17 @@ module ActiveRecord
|
|
356
355
|
if attributes.is_a?(Array)
|
357
356
|
attributes.collect { |attr| _create_record(attr, raise, &block) }
|
358
357
|
else
|
358
|
+
record = build_record(attributes, &block)
|
359
359
|
transaction do
|
360
|
-
|
361
|
-
|
362
|
-
insert_record(record, true, raise) {
|
360
|
+
result = nil
|
361
|
+
add_to_target(record) do
|
362
|
+
result = insert_record(record, true, raise) {
|
363
363
|
@_was_loaded = loaded?
|
364
|
-
@association_ids = nil
|
365
364
|
}
|
366
365
|
end
|
366
|
+
raise ActiveRecord::Rollback unless result
|
367
367
|
end
|
368
|
+
record
|
368
369
|
end
|
369
370
|
end
|
370
371
|
|
@@ -396,6 +397,7 @@ module ActiveRecord
|
|
396
397
|
|
397
398
|
delete_records(existing_records, method) if existing_records.any?
|
398
399
|
records.each { |record| target.delete(record) }
|
400
|
+
@association_ids = nil
|
399
401
|
|
400
402
|
records.each { |record| callback(:after_remove, record) }
|
401
403
|
end
|
@@ -408,9 +410,9 @@ module ActiveRecord
|
|
408
410
|
end
|
409
411
|
|
410
412
|
def replace_records(new_target, original_target)
|
411
|
-
delete(target
|
413
|
+
delete(difference(target, new_target))
|
412
414
|
|
413
|
-
unless concat(new_target
|
415
|
+
unless concat(difference(new_target, target))
|
414
416
|
@target = original_target
|
415
417
|
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
|
416
418
|
"new records could not be saved."
|
@@ -420,7 +422,7 @@ module ActiveRecord
|
|
420
422
|
end
|
421
423
|
|
422
424
|
def replace_common_records_in_memory(new_target, original_target)
|
423
|
-
common_records = new_target
|
425
|
+
common_records = intersection(new_target, original_target)
|
424
426
|
common_records.each do |record|
|
425
427
|
skip_callbacks = true
|
426
428
|
replace_on_target(record, @target.index(record), skip_callbacks)
|
@@ -436,13 +438,14 @@ module ActiveRecord
|
|
436
438
|
unless owner.new_record?
|
437
439
|
result &&= insert_record(record, true, raise) {
|
438
440
|
@_was_loaded = loaded?
|
439
|
-
@association_ids = nil
|
440
441
|
}
|
441
442
|
end
|
442
443
|
end
|
443
444
|
end
|
444
445
|
|
445
|
-
|
446
|
+
raise ActiveRecord::Rollback unless result
|
447
|
+
|
448
|
+
records
|
446
449
|
end
|
447
450
|
|
448
451
|
def replace_on_target(record, index, skip_callbacks)
|
@@ -457,6 +460,7 @@ module ActiveRecord
|
|
457
460
|
if index
|
458
461
|
target[index] = record
|
459
462
|
elsif @_was_loaded || !loaded?
|
463
|
+
@association_ids = nil
|
460
464
|
target << record
|
461
465
|
end
|
462
466
|
|