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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac2296e419c6f32f6ed2e2dbe92a344884d1197b8287bb6c67783a1587c31c72
4
- data.tar.gz: 523f4b66265e7ca8b4d67b19ecd13a547f7ad55acbdbd8190ec1e48a1cb4993e
3
+ metadata.gz: fff8caa10888c5cc1aee062b08ac4c4df6e5911e9b4c592b3e0c89c3faedf089
4
+ data.tar.gz: aebe5eb8c7b8624fc2bbe05f42c4c6e8ba5ef8122f519e4e2f984f83d1ac8762
5
5
  SHA512:
6
- metadata.gz: 463b978de4299a651821f4bf66ce219ba3def30f32d8fbb790086d10b869526578c2f5b441a1c0c5d368c03906e833a86b5ed88cda1a2f983e5769c04bf7efb2
7
- data.tar.gz: 5ab230e714c07790210516fbb760007fbbb49875a4021950b8e5d2c8ab77e132240f632ee50a62ee25dc58f629663f6d9802bee626d870d456284e3d4130ed3e
6
+ metadata.gz: 6d60f48c25171229b660274b31ae90689f402d0ea1f46fdf2c63467a550765520b46afb70ff683a8beca75da7ddb86629ba5f58e276667a784d37653f3a94688
7
+ data.tar.gz: '06973354f3d5158e1ade0f2898577d772b6669d622b176010b6176dbb8b02e5f67c611fbb55668bfee9c93ea873c1183cd28ba30e778a5a6692d0e050a9a3794'
data/CHANGELOG.md CHANGED
@@ -1,4 +1,34 @@
1
- ## Next Release
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
- do like
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
- previous_value = Bullet.enable?
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
- result
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
- result
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
- result
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
- result
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(sql, binds = [], preparable: nil, &block)
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 preloaders_for_one(association, records, scope, polymorphic_parent)
66
+ def call
67
67
  if Bullet.start?
68
- records.compact!
69
- if records.first.class.name !~ /^HABTM_/
70
- records.each { |record| Bullet::Detector::Association.add_object_associations(record, association) }
71
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
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
- def preloaders_for_reflection(reflection, records, scope)
80
+ ::ActiveRecord::Associations::Preloader::Branch.prepend(
81
+ Module.new do
82
+ def preloaders_for_reflection(reflection, reflection_records)
78
83
  if Bullet.start?
79
- records.compact!
80
- if records.first.class.name !~ /^HABTM_/
81
- records.each { |record| Bullet::Detector::Association.add_object_associations(record, reflection.name) }
82
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, reflection.name)
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 preloaded_records
93
- if Bullet.start? && !defined?(@preloaded_records)
94
- source_preloaders.each do |source_preloader|
95
- reflection_name = source_preloader.send(:reflection).name
96
- source_preloader.send(:owners).each do |owner|
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(result_set, &block)
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(ar_parent, parent, row, seen, model_cache)
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(record, node, row, model_cache, id)
152
- result = super
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) unless @inversed
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 target
235
- result = super()
266
+ def reader
267
+ result = super
236
268
 
237
269
  if Bullet.start?
238
- if owner.class.name !~ /^HABTM_/ && !@inversed
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
- result
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)