From fb1da7a3f529e0d2922f413ba06b61728237fb54 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Sun, 22 May 2022 18:33:08 +0300 Subject: [PATCH] Skip resetting correct counter caches --- .../lib/active_record/counter_cache.rb | 6 ++++-- activerecord/test/cases/counter_cache_test.rb | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb index 2f73f9fdeb..05fadd655e 100644 --- a/activerecord/lib/active_record/counter_cache.rb +++ b/activerecord/lib/active_record/counter_cache.rb @@ -48,7 +48,9 @@ def reset_counters(id, *counters, touch: nil) reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? } counter_name = reflection.counter_cache_column - updates[counter_name] = object.send(counter_association).count(:all) + count_was = object.send(counter_name) + count = object.send(counter_association).count(:all) + updates[counter_name] = count if count != count_was end if touch @@ -59,7 +61,7 @@ def reset_counters(id, *counters, touch: nil) updates.merge!(touch_updates) end - unscoped.where(primary_key => object.id).update_all(updates) + unscoped.where(primary_key => object.id).update_all(updates) if updates.any? true end diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb index c492592986..52d34747df 100644 --- a/activerecord/test/cases/counter_cache_test.rb +++ b/activerecord/test/cases/counter_cache_test.rb @@ -114,6 +114,27 @@ class ::SpecialReply < ::Reply end end + test "reset counter skips query for correct counter" do + Topic.reset_counters(@topic.id, :replies_count) + + # SELECT "topics".* FROM "topics" WHERE "topics"."id" = ? LIMIT ? + # SELECT COUNT(*) FROM "topics" WHERE "topics"."type" IN (?, ?, ?, ?, ?) AND "topics"."parent_id" = ? + assert_queries(2) do + Topic.reset_counters(@topic.id, :replies_count) + end + end + + test "reset counter performs query for correct counter with touch: true" do + Topic.reset_counters(@topic.id, :replies_count) + + # SELECT "topics".* FROM "topics" WHERE "topics"."id" = ? LIMIT ? + # SELECT COUNT(*) FROM "topics" WHERE "topics"."type" IN (?, ?, ?, ?, ?) AND "topics"."parent_id" = ? + # UPDATE "topics" SET "updated_at" = ? WHERE "topics"."id" = ? + assert_queries(3) do + Topic.reset_counters(@topic.id, :replies_count, touch: true) + end + end + test "update counter with initial null value" do category = categories(:general) assert_equal 2, category.categorizations.count