diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 11a89366aa..544aec5e8b 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -61,7 +61,11 @@ module ActiveRecord def update_counters(by) if require_counter_update? && foreign_key_present? - reader.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch]) + if target && !stale_target? + target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch]) + else + counter_cache_target.update_counters(reflection.counter_cache_column => by, touch: reflection.options[:touch]) + end end end @@ -92,6 +96,11 @@ module ActiveRecord inverse && inverse.has_one? end + def counter_cache_target + primary_key = reflection.association_primary_key(klass) + klass.unscoped.where!(primary_key => owner._read_attribute(reflection.foreign_key)) + end + def stale_state result = owner._read_attribute(reflection.foreign_key) { |n| owner.send(:missing_attribute, n, caller) } result && result.to_s diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index f8d27f1c56..0b44515e00 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1205,7 +1205,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase reply1 = Reply.create!(title: "re: zoom", content: "speedy quick!") reply2 = Reply.create!(title: "re: zoom 2", content: "OMG lol!") - assert_queries(6) do + assert_queries(4) do topic.replies << [reply1, reply2] end