bullet 8.0.8 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -1
- data/README.md +29 -11
- data/lib/bullet/active_record70.rb +20 -6
- data/lib/bullet/active_record71.rb +20 -6
- data/lib/bullet/active_record72.rb +20 -6
- data/lib/bullet/active_record80.rb +20 -6
- data/lib/bullet/{active_record60.rb → active_record81.rb} +67 -35
- data/lib/bullet/dependency.rb +10 -58
- data/lib/bullet/detector/association.rb +2 -2
- data/lib/bullet/detector/n_plus_one_query.rb +22 -3
- data/lib/bullet/detector/unused_eager_loading.rb +1 -1
- data/lib/bullet/mongoid4x.rb +2 -0
- data/lib/bullet/mongoid5x.rb +2 -0
- data/lib/bullet/mongoid6x.rb +2 -0
- data/lib/bullet/mongoid7x.rb +2 -0
- data/lib/bullet/mongoid8x.rb +2 -0
- data/lib/bullet/mongoid9x.rb +2 -0
- data/lib/bullet/rack.rb +35 -2
- data/lib/bullet/registry/call_stack.rb +7 -2
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +26 -1
- metadata +31 -9
- data/lib/bullet/active_record4.rb +0 -199
- data/lib/bullet/active_record41.rb +0 -191
- data/lib/bullet/active_record42.rb +0 -261
- data/lib/bullet/active_record5.rb +0 -294
- data/lib/bullet/active_record52.rb +0 -276
- data/lib/bullet/active_record61.rb +0 -303
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fff8caa10888c5cc1aee062b08ac4c4df6e5911e9b4c592b3e0c89c3faedf089
|
|
4
|
+
data.tar.gz: aebe5eb8c7b8624fc2bbe05f42c4c6e8ba5ef8122f519e4e2f984f83d1ac8762
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6d60f48c25171229b660274b31ae90689f402d0ea1f46fdf2c63467a550765520b46afb70ff683a8beca75da7ddb86629ba5f58e276667a784d37653f3a94688
|
|
7
|
+
data.tar.gz: '06973354f3d5158e1ade0f2898577d772b6669d622b176010b6176dbb8b02e5f67c611fbb55668bfee9c93ea873c1183cd28ba30e778a5a6692d0e050a9a3794'
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,34 @@
|
|
|
1
|
-
##
|
|
1
|
+
## Unreleased
|
|
2
|
+
|
|
3
|
+
## 8.2.0 (08/29/2026)
|
|
4
|
+
|
|
5
|
+
* Add thread-safe `Bullet.pause`, `Bullet.resume`, `Bullet.paused?`, and `Bullet.skip` APIs
|
|
6
|
+
* Add configurable footer positioning
|
|
7
|
+
* Fix unused eager loading false positives when N+1 detection is disabled
|
|
8
|
+
* Fix unused eager loading false positives for conditional `has_many :through` associations
|
|
9
|
+
* Fix Ruby 4.0 compatibility issues
|
|
10
|
+
* Drop support for ActiveRecord versions older than 7 and Mongoid versions older than 8
|
|
11
|
+
|
|
12
|
+
## 8.1.3 (06/02/2026)
|
|
13
|
+
|
|
14
|
+
* Handle inversed polymorphic belongs_to false positives
|
|
15
|
+
|
|
16
|
+
## 8.1.2 (05/25/2026)
|
|
17
|
+
|
|
18
|
+
* Skip N+1 detection for optional polymorphic `belongs_to` whose `*_type` column is nil. ActiveRecord short-circuits the reader to nil without issuing SQL, so the access cannot represent an N+1 query and preloading would be a no-op.
|
|
19
|
+
* Fix `Set#<<` corruption in `UnusedEagerLoading#add_eager_loadings` split branch
|
|
20
|
+
|
|
21
|
+
## 8.1.1 (04/23/2026)
|
|
22
|
+
|
|
23
|
+
* Fix ActiveRecord 8.1 patch-level method signature compatibility; test against Rails 8.1.3.
|
|
24
|
+
* Handle string associations in safelist for Action Text
|
|
25
|
+
* Enhance N+1 query detection by including caller stack in association calls
|
|
26
|
+
* Update external links in README.md
|
|
27
|
+
|
|
28
|
+
## 8.1.0 (10/23/2025)
|
|
29
|
+
|
|
30
|
+
* Make `get_relation` private
|
|
31
|
+
* Support Rails 8.1
|
|
2
32
|
|
|
3
33
|
## 8.0.8 (05/30/2025)
|
|
4
34
|
|
data/README.md
CHANGED
|
@@ -17,10 +17,9 @@ If you use activerecord 3.x, please use bullet < 5.5.0
|
|
|
17
17
|
|
|
18
18
|
## External Introduction
|
|
19
19
|
|
|
20
|
-
* [http://railscasts.com/episodes/372-bullet](http://railscasts.com/episodes/372-bullet)
|
|
21
|
-
* [http://ruby5.envylabs.com/episodes/9-episode-8-september-8-2009](http://ruby5.envylabs.com/episodes/9-episode-8-september-8-2009)
|
|
22
|
-
* [http://railslab.newrelic.com/2009/10/23/episode-19-on-the-edge-part-1](http://railslab.newrelic.com/2009/10/23/episode-19-on-the-edge-part-1)
|
|
23
20
|
* [https://rubyonrails.org/2009/10/22/community-highlights](https://rubyonrails.org/2009/10/22/community-highlights)
|
|
21
|
+
* [https://www.shakacode.com/blog/eliminate-N-1-queries-with-bullet/](https://www.shakacode.com/blog/eliminate-N-1-queries-with-bullet/)
|
|
22
|
+
* [https://reinteractive.com/articles/ruby-on-rails-community/elevating-your-code-quality-bullet-gem-and-query-prevention-in-testing](https://reinteractive.com/articles/ruby-on-rails-community/elevating-your-code-quality-bullet-gem-and-query-prevention-in-testing)
|
|
24
23
|
|
|
25
24
|
## Install
|
|
26
25
|
|
|
@@ -70,11 +69,16 @@ config.after_initialize do
|
|
|
70
69
|
Bullet.airbrake = true
|
|
71
70
|
Bullet.rollbar = true
|
|
72
71
|
Bullet.add_footer = true
|
|
72
|
+
Bullet.footer_position = 'bottom_left' # or 'bottom_right', 'top_left', 'top_right'
|
|
73
73
|
Bullet.skip_html_injection = false
|
|
74
|
+
Bullet.skip_http_headers = false
|
|
74
75
|
Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
|
|
75
76
|
Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware', ['my_file.rb', 'my_method'], ['my_file.rb', 16..20] ]
|
|
76
77
|
Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' }
|
|
77
78
|
Bullet.opentelemetry = true
|
|
79
|
+
Bullet.raise = false
|
|
80
|
+
Bullet.always_append_html_body = false
|
|
81
|
+
Bullet.skip_user_in_notification = false
|
|
78
82
|
end
|
|
79
83
|
```
|
|
80
84
|
|
|
@@ -82,6 +86,7 @@ The notifier of Bullet is a wrap of [uniform_notifier](https://github.com/flyerh
|
|
|
82
86
|
|
|
83
87
|
The code above will enable all of the Bullet notification systems:
|
|
84
88
|
* `Bullet.enable`: enable Bullet gem, otherwise do nothing
|
|
89
|
+
* `Bullet.sentry`: add notifications to sentry
|
|
85
90
|
* `Bullet.alert`: pop up a JavaScript alert in the browser
|
|
86
91
|
* `Bullet.bullet_logger`: log to the Bullet log file (Rails.root/log/bullet.log)
|
|
87
92
|
* `Bullet.console`: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
|
|
@@ -89,11 +94,11 @@ The code above will enable all of the Bullet notification systems:
|
|
|
89
94
|
* `Bullet.rails_logger`: add warnings directly to the Rails log
|
|
90
95
|
* `Bullet.honeybadger`: add notifications to Honeybadger
|
|
91
96
|
* `Bullet.bugsnag`: add notifications to bugsnag
|
|
92
|
-
* `Bullet.airbrake`: add notifications to airbrake
|
|
93
97
|
* `Bullet.appsignal`: add notifications to AppSignal
|
|
98
|
+
* `Bullet.airbrake`: add notifications to airbrake
|
|
94
99
|
* `Bullet.rollbar`: add notifications to rollbar
|
|
95
|
-
* `Bullet.sentry`: add notifications to sentry
|
|
96
100
|
* `Bullet.add_footer`: adds the details in the bottom left corner of the page. Double click the footer or use close button to hide footer.
|
|
101
|
+
* `Bullet.footer_position`: position of the footer on the page. Valid values are 'bottom_left' (default), 'bottom_right', 'top_left', or 'top_right'. This is useful when the default position clashes with browser UI elements like Chrome's URL preview.
|
|
97
102
|
* `Bullet.skip_html_injection`: prevents Bullet from injecting code into the returned HTML. This must be false for receiving alerts, showing the footer or console logging.
|
|
98
103
|
* `Bullet.skip_http_headers`: don't add headers to API requests, and remove the javascript that relies on them. Note that this prevents bullet from logging warnings to the browser console or updating the footer.
|
|
99
104
|
* `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
|
|
@@ -134,23 +139,34 @@ Bullet.add_safelist :type => :unused_eager_loading, :class_name => "Post", :asso
|
|
|
134
139
|
Bullet.add_safelist :type => :counter_cache, :class_name => "Country", :association => :cities
|
|
135
140
|
```
|
|
136
141
|
|
|
142
|
+
## Skip Bullet in specific actions
|
|
143
|
+
|
|
137
144
|
If you want to skip bullet in some specific controller actions, you can
|
|
138
|
-
|
|
145
|
+
use `Bullet.skip`, which is thread-safe and works correctly in multi-threaded
|
|
146
|
+
environments like Puma.
|
|
139
147
|
|
|
140
148
|
```ruby
|
|
141
149
|
class ApplicationController < ActionController::Base
|
|
142
150
|
around_action :skip_bullet, if: -> { defined?(Bullet) }
|
|
143
151
|
|
|
144
152
|
def skip_bullet
|
|
145
|
-
|
|
146
|
-
Bullet.enable = false
|
|
147
|
-
yield
|
|
148
|
-
ensure
|
|
149
|
-
Bullet.enable = previous_value
|
|
153
|
+
Bullet.skip { yield }
|
|
150
154
|
end
|
|
151
155
|
end
|
|
152
156
|
```
|
|
153
157
|
|
|
158
|
+
For more granular control, you can also use `Bullet.pause` and `Bullet.resume`:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
Bullet.pause # Temporarily disable detection for current thread
|
|
162
|
+
Bullet.resume # Re-enable detection for current thread
|
|
163
|
+
Bullet.paused? # Check if detection is paused for current thread
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Note**: Do not toggle `Bullet.enable` at runtime, as it modifies a global
|
|
167
|
+
flag that is not thread-safe. Use `Bullet.skip`, `Bullet.pause`, or
|
|
168
|
+
`Bullet.start_request`/`Bullet.end_request` instead.
|
|
169
|
+
|
|
154
170
|
## Log
|
|
155
171
|
|
|
156
172
|
The Bullet log `log/bullet.log` will look something like this:
|
|
@@ -256,6 +272,8 @@ config.after_initialize do
|
|
|
256
272
|
end
|
|
257
273
|
```
|
|
258
274
|
|
|
275
|
+
**Note:** Controller and integration tests work automatically because Bullet's Rack middleware wraps each HTTP request with `Bullet.start_request` and `Bullet.end_request`. However, model tests and other tests that don't go through the Rack middleware (like direct model method calls) require manual wrapping with the test helper code below.
|
|
276
|
+
|
|
259
277
|
Then wrap each test in the Bullet api.
|
|
260
278
|
|
|
261
279
|
With RSpec:
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
|
+
|
|
113
|
+
def through_preloaders
|
|
114
|
+
if Bullet.start? && !defined?(@through_preloaders)
|
|
115
|
+
preloaders = super
|
|
116
|
+
preloaders.each do |preloader|
|
|
117
|
+
reflection_name = preloader.send(:reflection).name
|
|
118
|
+
preloader.send(:owners).each do |owner|
|
|
119
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
else
|
|
123
|
+
super
|
|
124
|
+
end
|
|
125
|
+
end
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -232,13 +246,13 @@ module Bullet
|
|
|
232
246
|
|
|
233
247
|
def empty?
|
|
234
248
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
235
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
249
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
236
250
|
end
|
|
237
251
|
super
|
|
238
252
|
end
|
|
239
253
|
|
|
240
254
|
def include?(object)
|
|
241
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
|
|
255
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations) if Bullet.start?
|
|
242
256
|
super
|
|
243
257
|
end
|
|
244
258
|
end
|
|
@@ -280,11 +294,10 @@ module Bullet
|
|
|
280
294
|
::ActiveRecord::Associations::HasManyAssociation.prepend(
|
|
281
295
|
Module.new do
|
|
282
296
|
def empty?
|
|
283
|
-
result = super
|
|
284
297
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
285
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
298
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
286
299
|
end
|
|
287
|
-
|
|
300
|
+
super
|
|
288
301
|
end
|
|
289
302
|
|
|
290
303
|
def count_records
|
|
@@ -307,7 +320,8 @@ module Bullet
|
|
|
307
320
|
)
|
|
308
321
|
Bullet::Detector::NPlusOneQuery.call_association(
|
|
309
322
|
proxy_association.owner,
|
|
310
|
-
proxy_association.reflection.name
|
|
323
|
+
proxy_association.reflection.name,
|
|
324
|
+
caller_locations
|
|
311
325
|
)
|
|
312
326
|
end
|
|
313
327
|
super(column_name)
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
|
+
|
|
113
|
+
def through_preloaders
|
|
114
|
+
if Bullet.start? && !defined?(@through_preloaders)
|
|
115
|
+
preloaders = super
|
|
116
|
+
preloaders.each do |preloader|
|
|
117
|
+
reflection_name = preloader.send(:reflection).name
|
|
118
|
+
preloader.send(:owners).each do |owner|
|
|
119
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
else
|
|
123
|
+
super
|
|
124
|
+
end
|
|
125
|
+
end
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -232,13 +246,13 @@ module Bullet
|
|
|
232
246
|
|
|
233
247
|
def empty?
|
|
234
248
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
235
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
249
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
236
250
|
end
|
|
237
251
|
super
|
|
238
252
|
end
|
|
239
253
|
|
|
240
254
|
def include?(object)
|
|
241
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
|
|
255
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations) if Bullet.start?
|
|
242
256
|
super
|
|
243
257
|
end
|
|
244
258
|
end
|
|
@@ -280,11 +294,10 @@ module Bullet
|
|
|
280
294
|
::ActiveRecord::Associations::HasManyAssociation.prepend(
|
|
281
295
|
Module.new do
|
|
282
296
|
def empty?
|
|
283
|
-
result = super
|
|
284
297
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
285
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
298
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
286
299
|
end
|
|
287
|
-
|
|
300
|
+
super
|
|
288
301
|
end
|
|
289
302
|
|
|
290
303
|
def count_records
|
|
@@ -307,7 +320,8 @@ module Bullet
|
|
|
307
320
|
)
|
|
308
321
|
Bullet::Detector::NPlusOneQuery.call_association(
|
|
309
322
|
proxy_association.owner,
|
|
310
|
-
proxy_association.reflection.name
|
|
323
|
+
proxy_association.reflection.name,
|
|
324
|
+
caller_locations
|
|
311
325
|
)
|
|
312
326
|
end
|
|
313
327
|
super(column_name)
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
|
+
|
|
113
|
+
def through_preloaders
|
|
114
|
+
if Bullet.start? && !defined?(@through_preloaders)
|
|
115
|
+
preloaders = super
|
|
116
|
+
preloaders.each do |preloader|
|
|
117
|
+
reflection_name = preloader.send(:reflection).name
|
|
118
|
+
preloader.send(:owners).each do |owner|
|
|
119
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
else
|
|
123
|
+
super
|
|
124
|
+
end
|
|
125
|
+
end
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -232,13 +246,13 @@ module Bullet
|
|
|
232
246
|
|
|
233
247
|
def empty?
|
|
234
248
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
235
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
249
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
236
250
|
end
|
|
237
251
|
super
|
|
238
252
|
end
|
|
239
253
|
|
|
240
254
|
def include?(object)
|
|
241
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
|
|
255
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations) if Bullet.start?
|
|
242
256
|
super
|
|
243
257
|
end
|
|
244
258
|
end
|
|
@@ -280,11 +294,10 @@ module Bullet
|
|
|
280
294
|
::ActiveRecord::Associations::HasManyAssociation.prepend(
|
|
281
295
|
Module.new do
|
|
282
296
|
def empty?
|
|
283
|
-
result = super
|
|
284
297
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
285
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
298
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
286
299
|
end
|
|
287
|
-
|
|
300
|
+
super
|
|
288
301
|
end
|
|
289
302
|
|
|
290
303
|
def count_records
|
|
@@ -307,7 +320,8 @@ module Bullet
|
|
|
307
320
|
)
|
|
308
321
|
Bullet::Detector::NPlusOneQuery.call_association(
|
|
309
322
|
proxy_association.owner,
|
|
310
|
-
proxy_association.reflection.name
|
|
323
|
+
proxy_association.reflection.name,
|
|
324
|
+
caller_locations
|
|
311
325
|
)
|
|
312
326
|
end
|
|
313
327
|
super(column_name)
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
|
+
|
|
113
|
+
def through_preloaders
|
|
114
|
+
if Bullet.start? && !defined?(@through_preloaders)
|
|
115
|
+
preloaders = super
|
|
116
|
+
preloaders.each do |preloader|
|
|
117
|
+
reflection_name = preloader.send(:reflection).name
|
|
118
|
+
preloader.send(:owners).each do |owner|
|
|
119
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
else
|
|
123
|
+
super
|
|
124
|
+
end
|
|
125
|
+
end
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -232,13 +246,13 @@ module Bullet
|
|
|
232
246
|
|
|
233
247
|
def empty?
|
|
234
248
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
235
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
249
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
236
250
|
end
|
|
237
251
|
super
|
|
238
252
|
end
|
|
239
253
|
|
|
240
254
|
def include?(object)
|
|
241
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
|
|
255
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations) if Bullet.start?
|
|
242
256
|
super
|
|
243
257
|
end
|
|
244
258
|
end
|
|
@@ -280,11 +294,10 @@ module Bullet
|
|
|
280
294
|
::ActiveRecord::Associations::HasManyAssociation.prepend(
|
|
281
295
|
Module.new do
|
|
282
296
|
def empty?
|
|
283
|
-
result = super
|
|
284
297
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
285
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
298
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
286
299
|
end
|
|
287
|
-
|
|
300
|
+
super
|
|
288
301
|
end
|
|
289
302
|
|
|
290
303
|
def count_records
|
|
@@ -307,7 +320,8 @@ module Bullet
|
|
|
307
320
|
)
|
|
308
321
|
Bullet::Detector::NPlusOneQuery.call_association(
|
|
309
322
|
proxy_association.owner,
|
|
310
|
-
proxy_association.reflection.name
|
|
323
|
+
proxy_association.reflection.name,
|
|
324
|
+
caller_locations
|
|
311
325
|
)
|
|
312
326
|
end
|
|
313
327
|
super(column_name)
|
|
@@ -16,8 +16,8 @@ module Bullet
|
|
|
16
16
|
require 'active_record'
|
|
17
17
|
::ActiveRecord::Base.extend(
|
|
18
18
|
Module.new do
|
|
19
|
-
def find_by_sql(
|
|
20
|
-
result = super
|
|
19
|
+
def find_by_sql(*args, **kwargs, &block)
|
|
20
|
+
result = super(*args, **kwargs, &block)
|
|
21
21
|
if Bullet.start?
|
|
22
22
|
if result.is_a? Array
|
|
23
23
|
if result.size > 1
|
|
@@ -61,25 +61,32 @@ module Bullet
|
|
|
61
61
|
end
|
|
62
62
|
)
|
|
63
63
|
|
|
64
|
-
::ActiveRecord::Associations::Preloader.prepend(
|
|
64
|
+
::ActiveRecord::Associations::Preloader::Batch.prepend(
|
|
65
65
|
Module.new do
|
|
66
|
-
def
|
|
66
|
+
def call
|
|
67
67
|
if Bullet.start?
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
@preloaders.each do |preloader|
|
|
69
|
+
preloader.records.each { |record|
|
|
70
|
+
Bullet::Detector::Association.add_object_associations(record, preloader.associations)
|
|
71
|
+
}
|
|
72
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(preloader.records, preloader.associations)
|
|
72
73
|
end
|
|
73
74
|
end
|
|
74
75
|
super
|
|
75
76
|
end
|
|
77
|
+
end
|
|
78
|
+
)
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
::ActiveRecord::Associations::Preloader::Branch.prepend(
|
|
81
|
+
Module.new do
|
|
82
|
+
def preloaders_for_reflection(reflection, reflection_records)
|
|
78
83
|
if Bullet.start?
|
|
79
|
-
|
|
80
|
-
if
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
reflection_records.compact!
|
|
85
|
+
if reflection_records.first.class.name !~ /^HABTM_/
|
|
86
|
+
reflection_records.each { |record|
|
|
87
|
+
Bullet::Detector::Association.add_object_associations(record, reflection.name)
|
|
88
|
+
}
|
|
89
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(reflection_records, reflection.name)
|
|
83
90
|
end
|
|
84
91
|
end
|
|
85
92
|
super
|
|
@@ -89,25 +96,41 @@ module Bullet
|
|
|
89
96
|
|
|
90
97
|
::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
|
|
91
98
|
Module.new do
|
|
92
|
-
def
|
|
93
|
-
if Bullet.start? && !defined?(@
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
def source_preloaders
|
|
100
|
+
if Bullet.start? && !defined?(@source_preloaders)
|
|
101
|
+
preloaders = super
|
|
102
|
+
preloaders.each do |preloader|
|
|
103
|
+
reflection_name = preloader.send(:reflection).name
|
|
104
|
+
preloader.send(:owners).each do |owner|
|
|
97
105
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
98
106
|
end
|
|
99
107
|
end
|
|
108
|
+
else
|
|
109
|
+
super
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def through_preloaders
|
|
114
|
+
if Bullet.start? && !defined?(@through_preloaders)
|
|
115
|
+
preloaders = super
|
|
116
|
+
preloaders.each do |preloader|
|
|
117
|
+
reflection_name = preloader.send(:reflection).name
|
|
118
|
+
preloader.send(:owners).each do |owner|
|
|
119
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
else
|
|
123
|
+
super
|
|
100
124
|
end
|
|
101
|
-
super
|
|
102
125
|
end
|
|
103
126
|
end
|
|
104
127
|
)
|
|
105
128
|
|
|
106
129
|
::ActiveRecord::Associations::JoinDependency.prepend(
|
|
107
130
|
Module.new do
|
|
108
|
-
def instantiate(
|
|
131
|
+
def instantiate(*args, **kwargs, &block)
|
|
109
132
|
@bullet_eager_loadings = {}
|
|
110
|
-
records = super
|
|
133
|
+
records = super(*args, **kwargs, &block)
|
|
111
134
|
|
|
112
135
|
if Bullet.start?
|
|
113
136
|
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
|
@@ -121,7 +144,8 @@ module Bullet
|
|
|
121
144
|
records
|
|
122
145
|
end
|
|
123
146
|
|
|
124
|
-
def construct(
|
|
147
|
+
def construct(*args, **kwargs, &block)
|
|
148
|
+
ar_parent, parent, row = args
|
|
125
149
|
if Bullet.start?
|
|
126
150
|
unless ar_parent.nil?
|
|
127
151
|
parent.children.each do |node|
|
|
@@ -144,12 +168,13 @@ module Bullet
|
|
|
144
168
|
end
|
|
145
169
|
end
|
|
146
170
|
|
|
147
|
-
super
|
|
171
|
+
super(*args, **kwargs, &block)
|
|
148
172
|
end
|
|
149
173
|
|
|
150
174
|
# call join associations
|
|
151
|
-
def construct_model(
|
|
152
|
-
|
|
175
|
+
def construct_model(*args, **kwargs, &block)
|
|
176
|
+
record, node = args
|
|
177
|
+
result = super(*args, **kwargs, &block)
|
|
153
178
|
|
|
154
179
|
if Bullet.start?
|
|
155
180
|
associations = [node.reflection.name]
|
|
@@ -178,6 +203,13 @@ module Bullet
|
|
|
178
203
|
end
|
|
179
204
|
super
|
|
180
205
|
end
|
|
206
|
+
|
|
207
|
+
def inversed_from_queries(record)
|
|
208
|
+
if Bullet.start? && inversable?(record)
|
|
209
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
|
210
|
+
end
|
|
211
|
+
super
|
|
212
|
+
end
|
|
181
213
|
end
|
|
182
214
|
)
|
|
183
215
|
|
|
@@ -200,7 +232,7 @@ module Bullet
|
|
|
200
232
|
end
|
|
201
233
|
end
|
|
202
234
|
end
|
|
203
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
235
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
204
236
|
if records.first.class.name !~ /^HABTM_/
|
|
205
237
|
if records.size > 1
|
|
206
238
|
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
|
@@ -216,13 +248,13 @@ module Bullet
|
|
|
216
248
|
|
|
217
249
|
def empty?
|
|
218
250
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
219
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
251
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
220
252
|
end
|
|
221
253
|
super
|
|
222
254
|
end
|
|
223
255
|
|
|
224
256
|
def include?(object)
|
|
225
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
|
|
257
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations) if Bullet.start?
|
|
226
258
|
super
|
|
227
259
|
end
|
|
228
260
|
end
|
|
@@ -231,11 +263,11 @@ module Bullet
|
|
|
231
263
|
::ActiveRecord::Associations::SingularAssociation.prepend(
|
|
232
264
|
Module.new do
|
|
233
265
|
# call has_one and belongs_to associations
|
|
234
|
-
def
|
|
235
|
-
result = super
|
|
266
|
+
def reader
|
|
267
|
+
result = super
|
|
236
268
|
|
|
237
269
|
if Bullet.start?
|
|
238
|
-
if owner.class.name !~ /^HABTM_/
|
|
270
|
+
if owner.class.name !~ /^HABTM_/
|
|
239
271
|
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
240
272
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
|
241
273
|
association = owner.association(reflection.through_reflection.name)
|
|
@@ -264,11 +296,10 @@ module Bullet
|
|
|
264
296
|
::ActiveRecord::Associations::HasManyAssociation.prepend(
|
|
265
297
|
Module.new do
|
|
266
298
|
def empty?
|
|
267
|
-
result = super
|
|
268
299
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
269
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
300
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
270
301
|
end
|
|
271
|
-
|
|
302
|
+
super
|
|
272
303
|
end
|
|
273
304
|
|
|
274
305
|
def count_records
|
|
@@ -291,7 +322,8 @@ module Bullet
|
|
|
291
322
|
)
|
|
292
323
|
Bullet::Detector::NPlusOneQuery.call_association(
|
|
293
324
|
proxy_association.owner,
|
|
294
|
-
proxy_association.reflection.name
|
|
325
|
+
proxy_association.reflection.name,
|
|
326
|
+
caller_locations
|
|
295
327
|
)
|
|
296
328
|
end
|
|
297
329
|
super(column_name)
|