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.

Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +214 -0
  3. data/lib/active_record/association_relation.rb +3 -3
  4. data/lib/active_record/associations.rb +9 -9
  5. data/lib/active_record/associations/alias_tracker.rb +1 -1
  6. data/lib/active_record/associations/association.rb +25 -10
  7. data/lib/active_record/associations/belongs_to_association.rb +14 -5
  8. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
  9. data/lib/active_record/associations/builder/belongs_to.rb +11 -2
  10. data/lib/active_record/associations/collection_association.rb +19 -15
  11. data/lib/active_record/associations/collection_proxy.rb +8 -34
  12. data/lib/active_record/associations/has_many_association.rb +9 -0
  13. data/lib/active_record/associations/has_many_through_association.rb +25 -1
  14. data/lib/active_record/associations/has_one_association.rb +8 -0
  15. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  16. data/lib/active_record/associations/join_dependency.rb +39 -64
  17. data/lib/active_record/associations/join_dependency/join_association.rb +12 -18
  18. data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
  19. data/lib/active_record/associations/singular_association.rb +4 -10
  20. data/lib/active_record/associations/through_association.rb +1 -1
  21. data/lib/active_record/attribute_methods/dirty.rb +15 -10
  22. data/lib/active_record/attribute_methods/read.rb +1 -1
  23. data/lib/active_record/autosave_association.rb +7 -2
  24. data/lib/active_record/callbacks.rb +4 -0
  25. data/lib/active_record/collection_cache_key.rb +2 -2
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +14 -8
  27. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +19 -6
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +5 -14
  33. data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
  34. data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
  35. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -19
  36. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  37. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -2
  38. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
  39. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
  40. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
  41. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
  42. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  43. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -26
  44. data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
  45. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
  46. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -0
  47. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
  48. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -4
  49. data/lib/active_record/core.rb +2 -1
  50. data/lib/active_record/counter_cache.rb +17 -13
  51. data/lib/active_record/enum.rb +1 -0
  52. data/lib/active_record/errors.rb +18 -12
  53. data/lib/active_record/gem_version.rb +1 -1
  54. data/lib/active_record/log_subscriber.rb +1 -1
  55. data/lib/active_record/migration.rb +1 -1
  56. data/lib/active_record/migration/compatibility.rb +15 -15
  57. data/lib/active_record/model_schema.rb +1 -1
  58. data/lib/active_record/persistence.rb +6 -5
  59. data/lib/active_record/query_cache.rb +4 -11
  60. data/lib/active_record/querying.rb +1 -1
  61. data/lib/active_record/railtie.rb +1 -3
  62. data/lib/active_record/relation.rb +39 -20
  63. data/lib/active_record/relation/calculations.rb +11 -8
  64. data/lib/active_record/relation/delegation.rb +30 -0
  65. data/lib/active_record/relation/finder_methods.rb +10 -8
  66. data/lib/active_record/relation/merger.rb +10 -11
  67. data/lib/active_record/relation/predicate_builder.rb +20 -14
  68. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  69. data/lib/active_record/relation/query_attribute.rb +5 -3
  70. data/lib/active_record/relation/query_methods.rb +45 -19
  71. data/lib/active_record/relation/spawn_methods.rb +1 -1
  72. data/lib/active_record/scoping/named.rb +2 -0
  73. data/lib/active_record/tasks/database_tasks.rb +1 -1
  74. data/lib/active_record/timestamp.rb +8 -1
  75. data/lib/active_record/transactions.rb +23 -20
  76. data/lib/active_record/type/serialized.rb +4 -0
  77. metadata +9 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a81ce578a98474e193314f6d806ee2f910d9d651fab445a14595154c41f6401
4
- data.tar.gz: 1a45823e0f6e0af4759af73c37e3a1b76bb9584e168b553bcfbca3208d2211e2
3
+ metadata.gz: 3a6a58445af3e133df097836131d528804585b935b40025174db5e3a284351b5
4
+ data.tar.gz: 4d1b7fbc93cb5582065167d8d8a197ed887133b06170c5acf0ab6a18dea29465
5
5
  SHA512:
6
- metadata.gz: f6390719d7140cda11b175cfb8c4ad62e502204a202a70d6bf532131f323b49f120c30ca8e28d9e35335bb03d52a596ae7dcdfb3b05e762ae78150c70625adae
7
- data.tar.gz: cc85711ffcbec0a1b04b4f9940c0752687f9b98e7b65950cf46b28df14c13c9399d15699134bb3c5835bd76fdc8b944b0a661483c685075605b270f3bbe774d0
6
+ metadata.gz: c91429dea93398c1c532da4f5a66435b73842887a4d0f86782dfb19ba3801dfa65e04410a26f503e18cbc434793f293c051c7844a3702a638f14443711d7d6ea
7
+ data.tar.gz: a224f223a6f2da2ac314fa2d6f0deb4befbb0a962cad19d8a5c93a769ffd45450d23df71d791dfadae0b56435207beee54e5126e2e9cee50e9678fbe233fff9b
@@ -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 |r|
35
- @association.set_inverse_instance r
36
- yield r if block_given?
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("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>)
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("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>)
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("developer_id" => id)</tt>)
1750
- # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
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
  #
@@ -33,7 +33,7 @@ module ActiveRecord
33
33
  elsif join.is_a?(Arel::Nodes::Join)
34
34
  join.left.name == name ? 1 : 0
35
35
  elsif join.is_a?(Hash)
36
- join.fetch(name, 0)
36
+ join[name]
37
37
  else
38
38
  raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
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
- !inversed && loaded? && @stale_state != stale_state
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 invertible_for?(record)
102
- inverse = record.association(inverse_reflection_for(record).name)
103
- inverse.target = owner
104
- inverse.inversed = true
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 invertible_for?(record)
112
- inverse = record.association(inverse_reflection_for(record).name)
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 target=(record)
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.id != owner._read_attribute(reflection.foreign_key)
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
- record._read_attribute(reflection.association_primary_key(record.class)) : nil
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
- private
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 saved_change_to_attribute?(foreign_key) && !new_record?
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
- old_record = klass.find_by(klass.primary_key => old_foreign_id)
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