Skip to content

Commit

Permalink
Merge pull request #655 from quintinm-dev/detect-bad-counts
Browse files Browse the repository at this point in the history
Detect n+1 count queries from ActiveRecord::Associations::CollectionProxy#count
  • Loading branch information
flyerhzm committed Apr 16, 2023
2 parents 75ae2f1 + b5634f9 commit 520278f
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
@@ -1,6 +1,8 @@
## Next Release

* Added `always_append_html_body` option, so the html snippet is always included even if there are no notifications
* Added detection of n+1 count queries from `count` method
* Changed the counter cache notification title to recommend using `size`

## 7.0.7 (03/01/2023)

Expand Down
9 changes: 9 additions & 0 deletions lib/bullet/active_record4.rb
Expand Up @@ -176,6 +176,15 @@ def has_cached_counter?(reflection = reflection())
result
end
end

::ActiveRecord::Associations::CollectionProxy.class_eval do
def count
if Bullet.start?
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
end
super
end
end
end
end
end
9 changes: 9 additions & 0 deletions lib/bullet/active_record41.rb
Expand Up @@ -168,6 +168,15 @@ def count_records
origin_count_records
end
end

::ActiveRecord::Associations::CollectionProxy.class_eval do
def count
if Bullet.start?
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
end
super
end
end
end
end
end
9 changes: 9 additions & 0 deletions lib/bullet/active_record42.rb
Expand Up @@ -233,6 +233,15 @@ def count_records
origin_count_records
end
end

::ActiveRecord::Associations::CollectionProxy.class_eval do
def count
if Bullet.start?
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
end
super
end
end
end
end
end
11 changes: 11 additions & 0 deletions lib/bullet/active_record5.rb
Expand Up @@ -260,6 +260,17 @@ def count_records
end
end
)

::ActiveRecord::Associations::CollectionProxy.prepend(
Module.new do
def count
if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
end
super
end
end
)
end
end
end
11 changes: 11 additions & 0 deletions lib/bullet/active_record52.rb
Expand Up @@ -242,6 +242,17 @@ def count_records
end
end
)

::ActiveRecord::Associations::CollectionProxy.prepend(
Module.new do
def count
if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
end
super
end
end
)
end
end
end
11 changes: 11 additions & 0 deletions lib/bullet/active_record60.rb
Expand Up @@ -269,6 +269,17 @@ def count_records
end
end
)

::ActiveRecord::Associations::CollectionProxy.prepend(
Module.new do
def count
if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
end
super
end
end
)
end
end
end
11 changes: 11 additions & 0 deletions lib/bullet/active_record61.rb
Expand Up @@ -269,6 +269,17 @@ def count_records
end
end
)

::ActiveRecord::Associations::CollectionProxy.prepend(
Module.new do
def count
if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
end
super
end
end
)
end
end
end
11 changes: 11 additions & 0 deletions lib/bullet/active_record70.rb
Expand Up @@ -279,6 +279,17 @@ def count_records
end
end
)

::ActiveRecord::Associations::CollectionProxy.prepend(
Module.new do
def count
if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
end
super
end
end
)
end
end
end
2 changes: 1 addition & 1 deletion lib/bullet/notification/counter_cache.rb
Expand Up @@ -8,7 +8,7 @@ def body
end

def title
'Need Counter Cache'
'Need Counter Cache with Active Record size'
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/bullet/notification/counter_cache_spec.rb
Expand Up @@ -8,7 +8,7 @@ module Notification
subject { CounterCache.new(Post, %i[comments votes]) }

it { expect(subject.body).to eq(' Post => [:comments, :votes]') }
it { expect(subject.title).to eq('Need Counter Cache') }
it { expect(subject.title).to eq('Need Counter Cache with Active Record size') }
end
end
end
24 changes: 24 additions & 0 deletions spec/integration/counter_cache_spec.rb
Expand Up @@ -64,5 +64,29 @@
expect(Bullet.collected_counter_cache_notifications).to be_empty
end
end

describe 'with count' do
it 'should need counter cache' do
Country.all.each { |country| country.cities.count }
expect(Bullet.collected_counter_cache_notifications).not_to be_empty
end

it 'should notify even with counter cache' do
Person.all.each { |person| person.pets.count }
expect(Bullet.collected_counter_cache_notifications).not_to be_empty
end

if ActiveRecord::VERSION::MAJOR > 4
it 'should not need counter cache for has_many through' do
Client.all.each { |client| client.firms.count }
expect(Bullet.collected_counter_cache_notifications).to be_empty
end
else
it 'should need counter cache for has_many through' do
Client.all.each { |client| client.firms.count }
expect(Bullet.collected_counter_cache_notifications).not_to be_empty
end
end
end
end
end

0 comments on commit 520278f

Please sign in to comment.