activerecord 5.2.0 → 5.2.3
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 +214 -0
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations.rb +9 -9
- 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/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 +25 -1
- 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.rb +39 -64
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -18
- data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
- data/lib/active_record/associations/singular_association.rb +4 -10
- data/lib/active_record/associations/through_association.rb +1 -1
- 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 +7 -2
- data/lib/active_record/callbacks.rb +4 -0
- data/lib/active_record/collection_cache_key.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +14 -8
- 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 +5 -0
- 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 +5 -14
- 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/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 +1 -4
- data/lib/active_record/core.rb +2 -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 +1 -1
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/migration/compatibility.rb +15 -15
- 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 +1 -3
- data/lib/active_record/relation.rb +39 -20
- data/lib/active_record/relation/calculations.rb +11 -8
- 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.rb +20 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/query_attribute.rb +5 -3
- data/lib/active_record/relation/query_methods.rb +45 -19
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/scoping/named.rb +2 -0
- data/lib/active_record/tasks/database_tasks.rb +1 -1
- data/lib/active_record/timestamp.rb +8 -1
- data/lib/active_record/transactions.rb +23 -20
- data/lib/active_record/type/serialized.rb +4 -0
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a6a58445af3e133df097836131d528804585b935b40025174db5e3a284351b5
|
4
|
+
data.tar.gz: 4d1b7fbc93cb5582065167d8d8a197ed887133b06170c5acf0ab6a18dea29465
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c91429dea93398c1c532da4f5a66435b73842887a4d0f86782dfb19ba3801dfa65e04410a26f503e18cbc434793f293c051c7844a3702a638f14443711d7d6ea
|
7
|
+
data.tar.gz: a224f223a6f2da2ac314fa2d6f0deb4befbb0a962cad19d8a5c93a769ffd45450d23df71d791dfadae0b56435207beee54e5126e2e9cee50e9678fbe233fff9b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,217 @@
|
|
1
|
+
## Rails 5.2.3 (March 27, 2019) ##
|
2
|
+
|
3
|
+
* Fix different `count` calculation when using `size` with manual `select` with DISTINCT.
|
4
|
+
|
5
|
+
Fixes #35214.
|
6
|
+
|
7
|
+
*Juani Villarejo*
|
8
|
+
|
9
|
+
* Fix prepared statements caching to be enabled even when query caching is enabled.
|
10
|
+
|
11
|
+
*Ryuta Kamizono*
|
12
|
+
|
13
|
+
* Don't allow `where` with invalid value matches to nil values.
|
14
|
+
|
15
|
+
Fixes #33624.
|
16
|
+
|
17
|
+
*Ryuta Kamizono*
|
18
|
+
|
19
|
+
* Restore an ability that class level `update` without giving ids.
|
20
|
+
|
21
|
+
Fixes #34743.
|
22
|
+
|
23
|
+
*Ryuta Kamizono*
|
24
|
+
|
25
|
+
* Fix join table column quoting with SQLite.
|
26
|
+
|
27
|
+
*Gannon McGibbon*
|
28
|
+
|
29
|
+
* Ensure that `delete_all` on collection proxy returns affected count.
|
30
|
+
|
31
|
+
*Ryuta Kamizono*
|
32
|
+
|
33
|
+
* Reset scope after delete on collection association to clear stale offsets of removed records.
|
34
|
+
|
35
|
+
*Gannon McGibbon*
|
36
|
+
|
37
|
+
|
38
|
+
## Rails 5.2.2.1 (March 11, 2019) ##
|
39
|
+
|
40
|
+
* No changes.
|
41
|
+
|
42
|
+
|
43
|
+
## Rails 5.2.2 (December 04, 2018) ##
|
44
|
+
|
45
|
+
* Do not ignore the scoping with query methods in the scope block.
|
46
|
+
|
47
|
+
*Ryuta Kamizono*
|
48
|
+
|
49
|
+
* Allow aliased attributes to be used in `#update_columns` and `#update`.
|
50
|
+
|
51
|
+
*Gannon McGibbon*
|
52
|
+
|
53
|
+
* Allow spaces in postgres table names.
|
54
|
+
|
55
|
+
Fixes issue where "user post" is misinterpreted as "\"user\".\"post\"" when quoting table names with the postgres
|
56
|
+
adapter.
|
57
|
+
|
58
|
+
*Gannon McGibbon*
|
59
|
+
|
60
|
+
* Cached columns_hash fields should be excluded from ResultSet#column_types
|
61
|
+
|
62
|
+
PR #34528 addresses the inconsistent behaviour when attribute is defined for an ignored column. The following test
|
63
|
+
was passing for SQLite and MySQL, but failed for PostgreSQL:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
class DeveloperName < ActiveRecord::Type::String
|
67
|
+
def deserialize(value)
|
68
|
+
"Developer: #{value}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class AttributedDeveloper < ActiveRecord::Base
|
73
|
+
self.table_name = "developers"
|
74
|
+
|
75
|
+
attribute :name, DeveloperName.new
|
76
|
+
|
77
|
+
self.ignored_columns += ["name"]
|
78
|
+
end
|
79
|
+
|
80
|
+
developer = AttributedDeveloper.create
|
81
|
+
developer.update_column :name, "name"
|
82
|
+
|
83
|
+
loaded_developer = AttributedDeveloper.where(id: developer.id).select("*").first
|
84
|
+
puts loaded_developer.name # should be "Developer: name" but it's just "name"
|
85
|
+
```
|
86
|
+
|
87
|
+
*Dmitry Tsepelev*
|
88
|
+
|
89
|
+
* Values of enum are frozen, raising an error when attempting to modify them.
|
90
|
+
|
91
|
+
*Emmanuel Byrd*
|
92
|
+
|
93
|
+
* `update_columns` now correctly raises `ActiveModel::MissingAttributeError`
|
94
|
+
if the attribute does not exist.
|
95
|
+
|
96
|
+
*Sean Griffin*
|
97
|
+
|
98
|
+
* Do not use prepared statement in queries that have a large number of binds.
|
99
|
+
|
100
|
+
*Ryuta Kamizono*
|
101
|
+
|
102
|
+
* Fix query cache to load before first request.
|
103
|
+
|
104
|
+
*Eileen M. Uchitelle*
|
105
|
+
|
106
|
+
* Fix collection cache key with limit and custom select to avoid ambiguous timestamp column error.
|
107
|
+
|
108
|
+
Fixes #33056.
|
109
|
+
|
110
|
+
*Federico Martinez*
|
111
|
+
|
112
|
+
* Fix duplicated record creation when using nested attributes with `create_with`.
|
113
|
+
|
114
|
+
*Darwin Wu*
|
115
|
+
|
116
|
+
* Fix regression setting children record in parent `before_save` callback.
|
117
|
+
|
118
|
+
*Guo Xiang Tan*
|
119
|
+
|
120
|
+
* Prevent leaking of user's DB credentials on `rails db:create` failure.
|
121
|
+
|
122
|
+
*bogdanvlviv*
|
123
|
+
|
124
|
+
* Clear mutation tracker before continuing the around callbacks.
|
125
|
+
|
126
|
+
*Yuya Tanaka*
|
127
|
+
|
128
|
+
* Prevent deadlocks when waiting for connection from pool.
|
129
|
+
|
130
|
+
*Brent Wheeldon*
|
131
|
+
|
132
|
+
* Avoid extra scoping when using `Relation#update` that was causing this method to change the current scope.
|
133
|
+
|
134
|
+
*Ryuta Kamizono*
|
135
|
+
|
136
|
+
* Fix numericality validator not to be affected by custom getter.
|
137
|
+
|
138
|
+
*Ryuta Kamizono*
|
139
|
+
|
140
|
+
* Fix bulk change table ignores comment option on PostgreSQL.
|
141
|
+
|
142
|
+
*Yoshiyuki Kinjo*
|
143
|
+
|
144
|
+
|
145
|
+
## Rails 5.2.1.1 (November 27, 2018) ##
|
146
|
+
|
147
|
+
* No changes.
|
148
|
+
|
149
|
+
|
150
|
+
## Rails 5.2.1 (August 07, 2018) ##
|
151
|
+
|
152
|
+
* PostgreSQL: Support new relkind for partitioned tables.
|
153
|
+
|
154
|
+
Fixes #33008.
|
155
|
+
|
156
|
+
*Yannick Schutz*
|
157
|
+
|
158
|
+
* Rollback parent transaction when children fails to update.
|
159
|
+
|
160
|
+
*Guillaume Malette*
|
161
|
+
|
162
|
+
* Fix default value for MySQL time types with specified precision.
|
163
|
+
|
164
|
+
*Nikolay Kondratyev*
|
165
|
+
|
166
|
+
* Fix `touch` option to behave consistently with `Persistence#touch` method.
|
167
|
+
|
168
|
+
*Ryuta Kamizono*
|
169
|
+
|
170
|
+
* Fix `save` in `after_create_commit` won't invoke extra `after_create_commit`.
|
171
|
+
|
172
|
+
Fixes #32831.
|
173
|
+
|
174
|
+
*Ryuta Kamizono*
|
175
|
+
|
176
|
+
* Fix logic on disabling commit callbacks so they are not called unexpectedly when errors occur.
|
177
|
+
|
178
|
+
*Brian Durand*
|
179
|
+
|
180
|
+
* Fix parent record should not get saved with duplicate children records.
|
181
|
+
|
182
|
+
Fixes #32940.
|
183
|
+
|
184
|
+
*Santosh Wadghule*
|
185
|
+
|
186
|
+
* Fix that association's after_touch is not called with counter cache.
|
187
|
+
|
188
|
+
Fixes #31559.
|
189
|
+
|
190
|
+
*Ryuta Kamizono*
|
191
|
+
|
192
|
+
* `becomes` should clear the mutation tracker which is created in `after_initialize`.
|
193
|
+
|
194
|
+
Fixes #32867.
|
195
|
+
|
196
|
+
*Ryuta Kamizono*
|
197
|
+
|
198
|
+
* Allow a belonging to parent object to be created from a new record.
|
199
|
+
|
200
|
+
*Jolyon Pawlyn*
|
201
|
+
|
202
|
+
* Fix that building record with assigning multiple has_one associations
|
203
|
+
wrongly persists through record.
|
204
|
+
|
205
|
+
Fixes #32511.
|
206
|
+
|
207
|
+
*Sam DeCesare*
|
208
|
+
|
209
|
+
* Fix relation merging when one of the relations is going to skip the
|
210
|
+
query cache.
|
211
|
+
|
212
|
+
*James Williams*
|
213
|
+
|
214
|
+
|
1
215
|
## Rails 5.2.0 (April 09, 2018) ##
|
2
216
|
|
3
217
|
* 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
|
@@ -241,7 +241,7 @@ module ActiveRecord
|
|
241
241
|
association
|
242
242
|
end
|
243
243
|
|
244
|
-
def association_cached?(name) # :nodoc
|
244
|
+
def association_cached?(name) # :nodoc:
|
245
245
|
@association_cache.key?(name)
|
246
246
|
end
|
247
247
|
|
@@ -1232,9 +1232,9 @@ module ActiveRecord
|
|
1232
1232
|
# * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
|
1233
1233
|
# * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
|
1234
1234
|
# * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
|
1235
|
-
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new(
|
1236
|
-
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new(
|
1237
|
-
# * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new(
|
1235
|
+
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new(firm_id: id)</tt>)
|
1236
|
+
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new(firm_id: id); c.save; c</tt>)
|
1237
|
+
# * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new(firm_id: id); c.save!</tt>)
|
1238
1238
|
# * <tt>Firm#clients.reload</tt>
|
1239
1239
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1240
1240
|
#
|
@@ -1405,9 +1405,9 @@ module ActiveRecord
|
|
1405
1405
|
# An Account class declares <tt>has_one :beneficiary</tt>, which will add:
|
1406
1406
|
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
|
1407
1407
|
# * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
|
1408
|
-
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new(
|
1409
|
-
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new(
|
1410
|
-
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new(
|
1408
|
+
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new(account_id: id)</tt>)
|
1409
|
+
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new(account_id: id); b.save; b</tt>)
|
1410
|
+
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new(account_id: id); b.save!; b</tt>)
|
1411
1411
|
# * <tt>Account#reload_beneficiary</tt>
|
1412
1412
|
#
|
1413
1413
|
# === Scopes
|
@@ -1746,8 +1746,8 @@ module ActiveRecord
|
|
1746
1746
|
# * <tt>Developer#projects.size</tt>
|
1747
1747
|
# * <tt>Developer#projects.find(id)</tt>
|
1748
1748
|
# * <tt>Developer#projects.exists?(...)</tt>
|
1749
|
-
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new(
|
1750
|
-
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new(
|
1749
|
+
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new(developer_id: id)</tt>)
|
1750
|
+
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new(developer_id: id); c.save; c</tt>)
|
1751
1751
|
# * <tt>Developer#projects.reload</tt>
|
1752
1752
|
# The declaration may include an +options+ hash to specialize the behavior of the association.
|
1753
1753
|
#
|
@@ -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
|