bullet 4.11.0 → 4.12.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
  SHA1:
3
- metadata.gz: db6af7eda5d3f19441a8e60b5aae5bf09d4dd3f8
4
- data.tar.gz: 94510322d9e3190c200e5b18351c9b11c255e19a
3
+ metadata.gz: b201e99b1db5ea0ae016eb415b8bdcb2141a0321
4
+ data.tar.gz: 072c423687b8482273549f30c2538edec5c3c03f
5
5
  SHA512:
6
- metadata.gz: 2f1be7c449021b691ba83e2ea42c39d0701ce5c89f6517c9218dc563eaac0d6a18e626025e113470d30a7d8ce9c77ab7da784b030f983b32784079dba3312bd1
7
- data.tar.gz: 0306d0092a4c164e5b650f7c3e5b42b4e3b16d3359bd82ff20e9b5b1cd2414af1e236f91a07a147ed374d4d9bf6d98a1eedb50b1dd4bf09e9922a222568bdfb1
6
+ metadata.gz: 624bfcc8a8f2044699d19e598729cba0bf858e054002b435a31cce643d1bc3834139dad14ea510ef573a31059ce13f4b5c1dd892404645cca8d77e47264db794
7
+ data.tar.gz: ffaf8125f6797fd85b42be44f645e835796d623bc8b656662b8bd7387ac3b92882d4f2daaf2c50c04aced38113d7c96fbd8b3bdf631bd532c0a02663e221e1d1
data/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Next Release
2
2
 
3
- ## 4.11.0
3
+ ## 4.12.0
4
+
5
+ * Fix false n+1 queries caused by inversed objects.
6
+ * Replace .id with .primary_key_value
7
+ * Rename bullet_ar_key to bullet_key
8
+ * Fix rails sse detect
9
+ * Fix bullet using in test environment
10
+ * Memoize whoami
11
+
12
+ ## 4.11.0 (06/24/2014)
4
13
 
5
14
  * Support empty? call on ar associations
6
15
  * Skip detecting if object is a new record
data/Gemfile.mongoid-4.0 CHANGED
@@ -5,7 +5,7 @@ gemspec
5
5
  gem 'rails', '~> 4.0.5'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
- gem 'mongoid', '~> 4.0.0.beta2'
8
+ gem 'mongoid', '~> 4.0.0'
9
9
 
10
10
  gem "rspec"
11
11
  gem "guard"
data/Gemfile.rails-3.2 CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2.18'
5
+ gem 'rails', '~> 3.2.19'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
data/Gemfile.rails-4.0 CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 4.0.5'
5
+ gem 'rails', '~> 4.0.8'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
data/Gemfile.rails-4.1 CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 4.1.1'
5
+ gem 'rails', '~> 4.1.4'
6
6
  gem 'sqlite3'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
data/README.md CHANGED
@@ -60,7 +60,7 @@ config.after_initialize do
60
60
  end
61
61
  ```
62
62
 
63
- The notifier of bullet is a wrap of [uniform_notifier](https://github.com/flyerhzm/uniform_notifier)
63
+ The notifier of Bullet is a wrap of [uniform_notifier](https://github.com/flyerhzm/uniform_notifier)
64
64
 
65
65
  The code above will enable all seven of the Bullet notification systems:
66
66
  * `Bullet.enable`: enable Bullet gem, otherwise do nothing
@@ -70,25 +70,31 @@ The code above will enable all seven of the Bullet notification systems:
70
70
  * `Bullet.airbrake`: add notifications to airbrake
71
71
  * `Bullet.console`: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
72
72
  * `Bullet.growl`: pop up Growl warnings if your system has Growl installed. Requires a little bit of configuration
73
- * `Bullet.xmpp`: send XMPP/Jabber notifications to the receiver indicated. Note that the code will currently not handle the adding of contacts, so you will need to make both accounts indicated know each other manually before you will receive any notifications. If you restart the development server frequently, the 'coming online' sound for the bullet account may start to annoy - in this case set :show_online_status to false; you will still get notifications, but the bullet account won't announce it's online status anymore.
73
+ * `Bullet.xmpp`: send XMPP/Jabber notifications to the receiver indicated. Note that the code will currently not handle the adding of contacts, so you will need to make both accounts indicated know each other manually before you will receive any notifications. If you restart the development server frequently, the 'coming online' sound for the Bullet account may start to annoy - in this case set :show_online_status to false; you will still get notifications, but the Bullet account won't announce it's online status anymore.
74
74
  * `Bullet.raise`: raise errors, useful for making your specs fail unless they have optimized queries
75
75
  * `Bullet.add_footer`: adds the details in the bottom left corner of the page
76
76
  * `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
77
77
 
78
- Bullet also allows you to disable n_plus_one_query, unused_eager_loading
79
- and counter_cache detectors respectively.
78
+ Bullet also allows you to disable any of its detectors.
80
79
 
81
80
  ```ruby
82
- Bullet.n_plus_one_query_enable = false
81
+ # Each of these settings defaults to true
82
+
83
+ # Detect N+1 queries
84
+ Bullet.n_plus_one_query_enable = false
85
+
86
+ # Detect eager-loaded associations which are not used
83
87
  Bullet.unused_eager_loading_enable = false
84
- Bullet.counter_cache_enable = false
88
+
89
+ # Detect unnecessary COUNT queries which could be avoided
90
+ # with a counter_cache
91
+ Bullet.counter_cache_enable = false
85
92
  ```
86
93
 
87
94
  ## Whitelist
88
95
 
89
- Sometimes bullet may notify n plus one query, unused eager loading or
90
- counter cache you don't care about or they occur in the third party gems
91
- that you can't fix, you can add whitelist to bullet
96
+ Sometimes Bullet may notify you of query problems you don't care to fix, or
97
+ which come from outside your code. You can whitelist these to ignore them:
92
98
 
93
99
  ```ruby
94
100
  Bullet.add_whitelist :type => :n_plus_one_query, :class_name => "Post", :association => :comments
@@ -136,13 +142,13 @@ see [https://github.com/flyerhzm/uniform_notifier](https://github.com/flyerhzm/u
136
142
 
137
143
  ## Important
138
144
 
139
- If you find bullet does not work for you, *please disable your browser's cache*.
145
+ If you find Bullet does not work for you, *please disable your browser's cache*.
140
146
 
141
147
  ## Advanced
142
148
 
143
149
  ### Profile a job
144
150
 
145
- The bullet gem uses rack middleware to profile requests. If you want to use bullet without an http server, like to profile a job, you can use use profile method and fetch warnings
151
+ The Bullet gem uses rack middleware to profile requests. If you want to use Bullet without an http server, like to profile a job, you can use use profile method and fetch warnings
146
152
 
147
153
  ```ruby
148
154
  Bullet.profile do
@@ -153,7 +159,7 @@ warnings = Bullet.warnings
153
159
 
154
160
  ### Work with sinatra
155
161
 
156
- Configure and use bullet rack
162
+ Configure and use `Bullet::Rack`
157
163
 
158
164
  ```ruby
159
165
  configure :development do
@@ -165,7 +171,7 @@ end
165
171
 
166
172
  ### Run in tests
167
173
 
168
- First you need to enable bullet in test environment.
174
+ First you need to enable Bullet in test environment.
169
175
 
170
176
  ```ruby
171
177
  # config/environments/test.rb
@@ -176,34 +182,36 @@ config.after_initialize do
176
182
  end
177
183
  ```
178
184
 
179
- Then wrap each test in bullet api.
185
+ Then wrap each test in Bullet api.
180
186
 
181
187
  ```ruby
182
188
  # spec/spec_helper.rb
183
- config.before(:each) do
184
- Bullet.start_request if Bullet.enable?
185
- end
189
+ if Bullet.enable?
190
+ config.before(:each) do
191
+ Bullet.start_request
192
+ end
186
193
 
187
- config.after(:each) do
188
- Bullet.perform_out_of_channel_notifications if Bullet.enable? && Bullet.notification?
189
- Bullet.end_request if Bullet.enable?
194
+ config.after(:each) do
195
+ Bullet.perform_out_of_channel_notifications if Bullet.notification?
196
+ Bullet.end_request
197
+ end
190
198
  end
191
199
  ```
192
200
 
193
201
  ## Debug Mode
194
202
 
195
- Bullet outputs some details info, to enable debug mode, set DEBUG=true
196
- env.
203
+ Bullet outputs some details info, to enable debug mode, set
204
+ `BULLET_DEBUG=true` env.
197
205
 
198
206
  ## Contributors
199
207
 
200
208
  [https://github.com/flyerhzm/bullet/contributors](https://github.com/flyerhzm/bullet/contributors)
201
209
 
202
- ## Step by step example
210
+ ## Demo
203
211
 
204
- Bullet is designed to function as you browse through your application in development. It will alert you whenever it encounters N+1 queries or unused eager loading.
212
+ Bullet is designed to function as you browse through your application in development. To see it in action, follow these steps to create, detect, and fix example query problems.
205
213
 
206
- 1\. setup test environment
214
+ 1\. Create an example application
207
215
 
208
216
  ```
209
217
  $ rails new test_bullet
@@ -213,7 +221,7 @@ $ rails g scaffold comment name:string post_id:integer
213
221
  $ bundle exec rake db:migrate
214
222
  ```
215
223
 
216
- 2\. change `app/model/post.rb` and `app/model/comment.rb`
224
+ 2\. Change `app/model/post.rb` and `app/model/comment.rb`
217
225
 
218
226
  ```ruby
219
227
  class Post < ActiveRecord::Base
@@ -225,7 +233,7 @@ class Comment < ActiveRecord::Base
225
233
  end
226
234
  ```
227
235
 
228
- 3\. go to `rails c` and execute
236
+ 3\. Go to `rails c` and execute
229
237
 
230
238
  ```ruby
231
239
  post1 = Post.create(:name => 'first')
@@ -236,7 +244,7 @@ post2.comments.create(:name => 'third')
236
244
  post2.comments.create(:name => 'fourth')
237
245
  ```
238
246
 
239
- 4\. change the `app/views/posts/index.html.erb` to produce a N+1 query
247
+ 4\. Change the `app/views/posts/index.html.erb` to produce a N+1 query
240
248
 
241
249
  ```
242
250
  <% @posts.each do |post| %>
@@ -250,7 +258,7 @@ post2.comments.create(:name => 'fourth')
250
258
  <% end %>
251
259
  ```
252
260
 
253
- 5\. add bullet gem to `Gemfile`
261
+ 5\. Add the `bullet` gem to the `Gemfile`
254
262
 
255
263
  ```ruby
256
264
  gem "bullet"
@@ -262,7 +270,7 @@ And run
262
270
  bundle install
263
271
  ```
264
272
 
265
- 6\. enable the bullet gem in development, add a line to
273
+ 6\. enable the Bullet gem in development, add a line to
266
274
  `config/environments/development.rb`
267
275
 
268
276
  ```ruby
@@ -277,13 +285,13 @@ config.after_initialize do
277
285
  end
278
286
  ```
279
287
 
280
- 7\. start server
288
+ 7\. Start the server
281
289
 
282
290
  ```
283
291
  $ rails s
284
292
  ```
285
293
 
286
- 8\. input http://localhost:3000/posts in browser, then you will see a popup alert box says
294
+ 8\. Visit `http://localhost:3000/posts` in browser, and you will see a popup alert box that says
287
295
 
288
296
  ```
289
297
  The request has unused preload associations as follows:
@@ -292,7 +300,7 @@ The request has N+1 queries as follows:
292
300
  model: Post => associations: [comment]
293
301
  ```
294
302
 
295
- which means there is a N+1 query from post object to comments associations.
303
+ which means there is a N+1 query from the Post object to its Comment association.
296
304
 
297
305
  In the meanwhile, there's a log appended into `log/bullet.log` file
298
306
 
@@ -307,7 +315,7 @@ In the meanwhile, there's a log appended into `log/bullet.log` file
307
315
  /home/flyerhzm/Downloads/test_bullet/app/controllers/posts_controller.rb:7:in `index'
308
316
  ```
309
317
 
310
- The generated SQLs are
318
+ The generated SQL is:
311
319
 
312
320
  ```
313
321
  Post Load (1.0ms) SELECT * FROM "posts"
@@ -315,8 +323,7 @@ Comment Load (0.4ms) SELECT * FROM "comments" WHERE ("comments".post_id = 1)
315
323
  Comment Load (0.3ms) SELECT * FROM "comments" WHERE ("comments".post_id = 2)
316
324
  ```
317
325
 
318
-
319
- 9\. fix the N+1 query, change `app/controllers/posts_controller.rb` file
326
+ 9\. To fix the N+1 query, change `app/controllers/posts_controller.rb` file
320
327
 
321
328
  ```ruby
322
329
  def index
@@ -329,18 +336,18 @@ def index
329
336
  end
330
337
  ```
331
338
 
332
- 10\. refresh http://localhost:3000/posts page, no alert box and no log appended.
339
+ 10\. Refresh `http://localhost:3000/posts`. Now there's no alert box and nothing new in the log.
333
340
 
334
- The generated SQLs are
341
+ The generated SQL is:
335
342
 
336
343
  ```
337
344
  Post Load (0.5ms) SELECT * FROM "posts"
338
345
  Comment Load (0.5ms) SELECT "comments".* FROM "comments" WHERE ("comments".post_id IN (1,2))
339
346
  ```
340
347
 
341
- a N+1 query fixed. Cool!
348
+ N+1 query fixed. Cool!
342
349
 
343
- 11\. now simulate unused eager loading. Change
350
+ 11\. Now simulate unused eager loading. Change
344
351
  `app/controllers/posts_controller.rb` and
345
352
  `app/views/posts/index.html.erb`
346
353
 
@@ -366,7 +373,7 @@ end
366
373
  <% end %>
367
374
  ```
368
375
 
369
- 12\. refresh http://localhost:3000/posts page, then you will see a popup alert box says
376
+ 12\. Refresh `http://localhost:3000/posts`, and you will see a popup alert box that says
370
377
 
371
378
  ```
372
379
  The request has unused preload associations as follows:
@@ -375,14 +382,14 @@ The request has N+1 queries as follows:
375
382
  None
376
383
  ```
377
384
 
378
- In the meanwhile, there's a log appended into `log/bullet.log` file
385
+ Meanwhile, there's a line appended to `log/bullet.log`
379
386
 
380
387
  ```
381
388
  2009-08-25 21:13:22[INFO] Unused preload associations: PATH_INFO: /posts; model: Post => associations: [comments]·
382
389
  Remove from your finder: :include => [:comments]
383
390
  ```
384
391
 
385
- 13\. simulate counter_cache. Change `app/controllers/posts_controller.rb`
392
+ 13\. Simulate counter_cache. Change `app/controllers/posts_controller.rb`
386
393
  and `app/views/posts/index.html.erb`
387
394
 
388
395
  ```ruby
@@ -408,19 +415,18 @@ end
408
415
  <% end %>
409
416
  ```
410
417
 
411
- 14\. refresh http://localhost:3000/posts page, then you will see a popup alert box says
418
+ 14\. Refresh `http://localhost:3000/posts`, then you will see a popup alert box that says
412
419
 
413
420
  ```
414
421
  Need counter cache
415
422
  Post => [:comments]
416
423
  ```
417
424
 
418
- In the meanwhile, there's a log appended into `log/bullet.log` file.
425
+ Meanwhile, there's a line appended to `log/bullet.log`
419
426
 
420
427
  ```
421
428
  2009-09-11 10:07:10[INFO] Need Counter Cache
422
429
  Post => [:comments]
423
430
  ```
424
431
 
425
-
426
432
  Copyright (c) 2009 - 2014 Richard Huang (flyerhzm@gmail.com), released under the MIT license
data/bullet.gemspec CHANGED
@@ -17,8 +17,8 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.required_rubygems_version = ">= 1.3.6"
19
19
 
20
- s.add_runtime_dependency "activesupport"
21
- s.add_runtime_dependency "uniform_notifier", "~> 1.6.0"
20
+ s.add_runtime_dependency "activesupport", ">= 3.0.0"
21
+ s.add_runtime_dependency "uniform_notifier", ">= 1.6.0"
22
22
 
23
23
  s.files = `git ls-files`.split("\n")
24
24
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -119,7 +119,7 @@ module Bullet
119
119
  alias_method :origin_set_inverse_instance, :set_inverse_instance
120
120
  def set_inverse_instance(record, instance)
121
121
  if record && we_can_set_the_inverse_on_this?(record)
122
- Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
122
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(record, @reflection.inverse_of.name)
123
123
  end
124
124
  origin_set_inverse_instance(record, instance)
125
125
  end
@@ -108,7 +108,7 @@ module Bullet
108
108
  alias_method :origin_set_inverse_instance, :set_inverse_instance
109
109
  def set_inverse_instance(record)
110
110
  if record && invertible_for?(record)
111
- Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
111
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(record, inverse_reflection_for(record).name)
112
112
  end
113
113
  origin_set_inverse_instance(record)
114
114
  end
@@ -98,22 +98,12 @@ module Bullet
98
98
  alias_method :origin_reader, :reader
99
99
  def reader(force_reload = false)
100
100
  result = origin_reader(force_reload)
101
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
101
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
102
102
  Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
103
103
  result
104
104
  end
105
105
  end
106
106
 
107
- ::ActiveRecord::Associations::Association.class_eval do
108
- alias_method :origin_set_inverse_instance, :set_inverse_instance
109
- def set_inverse_instance(record)
110
- if record && invertible_for?(record)
111
- Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
112
- end
113
- origin_set_inverse_instance(record)
114
- end
115
- end
116
-
117
107
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
118
108
  alias_method :origin_has_cached_counter?, :has_cached_counter?
119
109
 
@@ -27,6 +27,7 @@ module Bullet
27
27
  def preloaders_on(association, records, scope)
28
28
  if records.first.class.name !~ /^HABTM_/
29
29
  records.each do |record|
30
+ next unless record
30
31
  Bullet::Detector::Association.add_object_associations(record, association)
31
32
  end
32
33
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
@@ -5,19 +5,19 @@ module Bullet
5
5
  def add_object_associations(object, associations)
6
6
  return unless Bullet.start?
7
7
  return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
8
- return unless object.id
8
+ return unless object.primary_key_value
9
9
 
10
- Bullet.debug("Detector::Association#add_object_associations", "object: #{object.bullet_ar_key}, associations: #{associations}")
11
- object_associations.add(object.bullet_ar_key, associations)
10
+ Bullet.debug("Detector::Association#add_object_associations", "object: #{object.bullet_key}, associations: #{associations}")
11
+ object_associations.add(object.bullet_key, associations)
12
12
  end
13
13
 
14
14
  def add_call_object_associations(object, associations)
15
15
  return unless Bullet.start?
16
16
  return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
17
- return unless object.id
17
+ return unless object.primary_key_value
18
18
 
19
- Bullet.debug("Detector::Association#add_call_object_associations", "object: #{object.bullet_ar_key}, associations: #{associations}")
20
- call_object_associations.add(object.bullet_ar_key, associations)
19
+ Bullet.debug("Detector::Association#add_call_object_associations", "object: #{object.bullet_key}, associations: #{associations}")
20
+ call_object_associations.add(object.bullet_key, associations)
21
21
  end
22
22
 
23
23
  private
@@ -48,13 +48,19 @@ module Bullet
48
48
  # impossible_objects keep the class to objects relationships
49
49
  # that the objects may not cause N+1 query.
50
50
  # e.g. { Post => ["Post:1", "Post:2"] }
51
- # Notice: impossible_objects are not accurate,
52
51
  # if find collection returns only one object, then the object is impossible object,
53
52
  # impossible_objects are used to avoid treating 1+1 query to N+1 query.
54
53
  def impossible_objects
55
54
  Thread.current[:bullet_impossible_objects]
56
55
  end
57
56
 
57
+ # inversed_objects keeps object relationships
58
+ # that association is inversed.
59
+ # e.g. { "Comment:1" => ["post"] }
60
+ def inversed_objects
61
+ Thread.current[:bullet_inversed_objects]
62
+ end
63
+
58
64
  # eager_loadings keep the object relationships
59
65
  # that the associations are preloaded by find :include.
60
66
  # e.g. { ["Post:1", "Post:2"] => [:comments, :user] }
@@ -5,10 +5,10 @@ module Bullet
5
5
  def add_counter_cache(object, associations)
6
6
  return unless Bullet.start?
7
7
  return unless Bullet.counter_cache_enable?
8
- return unless object.id
8
+ return unless object.primary_key_value
9
9
 
10
- Bullet.debug("Detector::CounterCache#add_counter_cache", "object: #{object.bullet_ar_key}, associations: #{associations}")
11
- if conditions_met?(object.bullet_ar_key, associations)
10
+ Bullet.debug("Detector::CounterCache#add_counter_cache", "object: #{object.bullet_key}, associations: #{associations}")
11
+ if conditions_met?(object.bullet_key, associations)
12
12
  create_notification object.class.to_s, associations
13
13
  end
14
14
  end
@@ -17,19 +17,19 @@ module Bullet
17
17
  return unless Bullet.start?
18
18
  return unless Bullet.counter_cache_enable?
19
19
  objects = Array(object_or_objects)
20
- return if objects.map(&:id).compact.empty?
20
+ return if objects.map(&:primary_key_value).compact.empty?
21
21
 
22
- Bullet.debug("Detector::CounterCache#add_possible_objects", "objects: #{objects.map(&:bullet_ar_key).join(', ')}")
23
- objects.each { |object| possible_objects.add object.bullet_ar_key }
22
+ Bullet.debug("Detector::CounterCache#add_possible_objects", "objects: #{objects.map(&:bullet_key).join(', ')}")
23
+ objects.each { |object| possible_objects.add object.bullet_key }
24
24
  end
25
25
 
26
26
  def add_impossible_object(object)
27
27
  return unless Bullet.start?
28
28
  return unless Bullet.counter_cache_enable?
29
- return unless object.id
29
+ return unless object.primary_key_value
30
30
 
31
- Bullet.debug("Detector::CounterCache#add_impossible_object", "object: #{object.bullet_ar_key}")
32
- impossible_objects.add object.bullet_ar_key
31
+ Bullet.debug("Detector::CounterCache#add_impossible_object", "object: #{object.bullet_key}")
32
+ impossible_objects.add object.bullet_key
33
33
  end
34
34
 
35
35
  private
@@ -50,8 +50,8 @@ module Bullet
50
50
  Thread.current[:bullet_counter_impossible_objects]
51
51
  end
52
52
 
53
- def conditions_met?(bullet_ar_key, associations)
54
- possible_objects.include?(bullet_ar_key) && !impossible_objects.include?(bullet_ar_key)
53
+ def conditions_met?(bullet_key, associations)
54
+ possible_objects.include?(bullet_key) && !impossible_objects.include?(bullet_key)
55
55
  end
56
56
  end
57
57
  end
@@ -10,12 +10,13 @@ module Bullet
10
10
  # if it is, keeps this unpreload associations and caller.
11
11
  def call_association(object, associations)
12
12
  return unless Bullet.start?
13
- return unless object.id
13
+ return unless object.primary_key_value
14
+ return if inversed_objects.include?(object.bullet_key, associations)
14
15
  add_call_object_associations(object, associations)
15
16
 
16
- Bullet.debug("Detector::NPlusOneQuery#call_association", "object: #{object.bullet_ar_key}, associations: #{associations}")
17
- if conditions_met?(object.bullet_ar_key, associations)
18
- Bullet.debug("detect n + 1 query", "object: #{object.bullet_ar_key}, associations: #{associations}")
17
+ Bullet.debug("Detector::NPlusOneQuery#call_association", "object: #{object.bullet_key}, associations: #{associations}")
18
+ if conditions_met?(object.bullet_key, associations)
19
+ Bullet.debug("detect n + 1 query", "object: #{object.bullet_key}, associations: #{associations}")
19
20
  create_notification caller_in_project, object.class.to_s, associations
20
21
  end
21
22
  end
@@ -24,19 +25,28 @@ module Bullet
24
25
  return unless Bullet.start?
25
26
  return unless Bullet.n_plus_one_query_enable?
26
27
  objects = Array(object_or_objects)
27
- return if objects.map(&:id).compact.empty?
28
+ return if objects.map(&:primary_key_value).compact.empty?
28
29
 
29
- Bullet.debug("Detector::NPlusOneQuery#add_possible_objects", "objects: #{objects.map(&:bullet_ar_key).join(', ')}")
30
- objects.each { |object| possible_objects.add object.bullet_ar_key }
30
+ Bullet.debug("Detector::NPlusOneQuery#add_possible_objects", "objects: #{objects.map(&:bullet_key).join(', ')}")
31
+ objects.each { |object| possible_objects.add object.bullet_key }
31
32
  end
32
33
 
33
34
  def add_impossible_object(object)
34
35
  return unless Bullet.start?
35
36
  return unless Bullet.n_plus_one_query_enable?
36
- return unless object.id
37
+ return unless object.primary_key_value
37
38
 
38
- Bullet.debug("Detector::NPlusOneQuery#add_impossible_object", "object: #{object.bullet_ar_key}")
39
- impossible_objects.add object.bullet_ar_key
39
+ Bullet.debug("Detector::NPlusOneQuery#add_impossible_object", "object: #{object.bullet_key}")
40
+ impossible_objects.add object.bullet_key
41
+ end
42
+
43
+ def add_inversed_object(object, association)
44
+ return unless Bullet.start?
45
+ return unless Bullet.n_plus_one_query_enable?
46
+ return unless object.primary_key_value
47
+
48
+ Bullet.debug("Detector::NPlusOneQuery#add_inversed_object", "object: #{object.bullet_key}, association: #{association}")
49
+ inversed_objects.add object.bullet_key, association
40
50
  end
41
51
 
42
52
  private
@@ -50,8 +60,8 @@ module Bullet
50
60
  end
51
61
 
52
62
  # decide whether the object.associations is unpreloaded or not.
53
- def conditions_met?(bullet_ar_key, associations)
54
- possible?(bullet_ar_key) && !impossible?(bullet_ar_key) && !association?(bullet_ar_key, associations)
63
+ def conditions_met?(bullet_key, associations)
64
+ possible?(bullet_key) && !impossible?(bullet_key) && !association?(bullet_key, associations)
55
65
  end
56
66
 
57
67
  def caller_in_project
@@ -63,17 +73,17 @@ module Bullet
63
73
  end
64
74
  end
65
75
 
66
- def possible?(bullet_ar_key)
67
- possible_objects.include? bullet_ar_key
76
+ def possible?(bullet_key)
77
+ possible_objects.include? bullet_key
68
78
  end
69
79
 
70
- def impossible?(bullet_ar_key)
71
- impossible_objects.include? bullet_ar_key
80
+ def impossible?(bullet_key)
81
+ impossible_objects.include? bullet_key
72
82
  end
73
83
 
74
84
  # check if object => associations already exists in object_associations.
75
- def association?(bullet_ar_key, associations)
76
- value = object_associations[bullet_ar_key]
85
+ def association?(bullet_key, associations)
86
+ value = object_associations[bullet_key]
77
87
  if value
78
88
  value.each do |v|
79
89
  result = v.is_a?(Hash) ? v.has_key?(associations) : v == associations