bullet 4.10.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/Gemfile +4 -4
  4. data/Gemfile.mongoid-4.0 +1 -1
  5. data/Gemfile.rails-3.2 +1 -1
  6. data/Gemfile.rails-4.0 +1 -1
  7. data/Gemfile.rails-4.1 +1 -1
  8. data/README.md +52 -46
  9. data/bullet.gemspec +2 -2
  10. data/lib/bullet/active_record3.rb +7 -1
  11. data/lib/bullet/active_record3x.rb +7 -1
  12. data/lib/bullet/active_record4.rb +7 -11
  13. data/lib/bullet/active_record41.rb +7 -0
  14. data/lib/bullet/detector/association.rb +13 -5
  15. data/lib/bullet/detector/counter_cache.rb +12 -9
  16. data/lib/bullet/detector/n_plus_one_query.rb +29 -16
  17. data/lib/bullet/detector/unused_eager_loading.rb +16 -15
  18. data/lib/bullet/ext/object.rb +10 -2
  19. data/lib/bullet/notification/base.rb +5 -5
  20. data/lib/bullet/rack.rb +10 -4
  21. data/lib/bullet/registry/object.rb +4 -4
  22. data/lib/bullet/version.rb +1 -1
  23. data/lib/bullet.rb +5 -2
  24. data/spec/bullet/detector/association_spec.rb +2 -2
  25. data/spec/bullet/detector/counter_cache_spec.rb +8 -8
  26. data/spec/bullet/detector/n_plus_one_query_spec.rb +27 -27
  27. data/spec/bullet/detector/unused_eager_loading_spec.rb +15 -15
  28. data/spec/bullet/ext/object_spec.rb +17 -3
  29. data/spec/bullet/notification/base_spec.rb +37 -0
  30. data/spec/bullet/rack_spec.rb +2 -2
  31. data/spec/bullet/registry/object_spec.rb +4 -4
  32. data/spec/bullet_spec.rb +2 -2
  33. data/spec/integration/active_record3/association_spec.rb +12 -2
  34. data/spec/integration/active_record4/association_spec.rb +11 -1
  35. data/spec/models/category.rb +1 -1
  36. data/spec/models/post.rb +1 -1
  37. data/spec/spec_helper.rb +2 -2
  38. data/spec/support/bullet_ext.rb +1 -1
  39. metadata +6 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e3badf3b077a980eaa5aff1923f4e73d702f5b91
4
- data.tar.gz: f62fd9855dca76718f1abd484052e8b9ec841088
3
+ metadata.gz: b201e99b1db5ea0ae016eb415b8bdcb2141a0321
4
+ data.tar.gz: 072c423687b8482273549f30c2538edec5c3c03f
5
5
  SHA512:
6
- metadata.gz: cd79339a18313dd651739d819f59d33ceee240ec595ff53a49b27133010d8a83e9274292907ccd99bd9b894b7d975c54e4a65b49f0907b08f0b70a4a994dc9e1
7
- data.tar.gz: 3dbb60cf0426b5cfb0d1fc5ac1bed620d139aafbf798eae0a7ebe94915a8b17fcc0a745b587313007a2922826f0b396f4be290dc353832f0c5e2618bedb29c50
6
+ metadata.gz: 624bfcc8a8f2044699d19e598729cba0bf858e054002b435a31cce643d1bc3834139dad14ea510ef573a31059ce13f4b5c1dd892404645cca8d77e47264db794
7
+ data.tar.gz: ffaf8125f6797fd85b42be44f645e835796d623bc8b656662b8bd7387ac3b92882d4f2daaf2c50c04aced38113d7c96fbd8b3bdf631bd532c0a02663e221e1d1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Next Release
2
2
 
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)
13
+
14
+ * Support empty? call on ar associations
15
+ * Skip detecting if object is a new record
16
+
17
+ ## 4.10.0 (06/06/2014)
18
+
19
+ * Handle join query smarter
20
+ * Support mongoid 4.0
21
+ * Thread safe
22
+ * Add debug mode
23
+
3
24
  ## 4.9.0 (04/30/2014)
4
25
 
5
26
  * Add Bullet.stacktrace_includes option
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
@@ -7,9 +7,9 @@ gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
9
 
10
- gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
10
+ gem 'rspec'
11
+ gem 'guard'
12
+ gem 'guard-rspec'
13
13
 
14
14
  gem 'coveralls', require: false
15
15
 
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")
@@ -97,6 +97,12 @@ module Bullet
97
97
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
98
98
  origin_last(*args)
99
99
  end
100
+
101
+ alias_method :origin_empty?, :empty?
102
+ def empty?
103
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
104
+ origin_empty?
105
+ end
100
106
  end
101
107
 
102
108
  ::ActiveRecord::Associations::AssociationProxy.class_eval do
@@ -113,7 +119,7 @@ module Bullet
113
119
  alias_method :origin_set_inverse_instance, :set_inverse_instance
114
120
  def set_inverse_instance(record, instance)
115
121
  if record && we_can_set_the_inverse_on_this?(record)
116
- Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
122
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(record, @reflection.inverse_of.name)
117
123
  end
118
124
  origin_set_inverse_instance(record, instance)
119
125
  end
@@ -85,6 +85,12 @@ module Bullet
85
85
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
86
86
  origin_load_target
87
87
  end
88
+
89
+ alias_method :origin_empty?, :empty?
90
+ def empty?
91
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
92
+ origin_empty?
93
+ end
88
94
  end
89
95
 
90
96
  ::ActiveRecord::Associations::SingularAssociation.class_eval do
@@ -102,7 +108,7 @@ module Bullet
102
108
  alias_method :origin_set_inverse_instance, :set_inverse_instance
103
109
  def set_inverse_instance(record)
104
110
  if record && invertible_for?(record)
105
- Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
111
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(record, inverse_reflection_for(record).name)
106
112
  end
107
113
  origin_set_inverse_instance(record)
108
114
  end
@@ -85,6 +85,12 @@ module Bullet
85
85
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
86
86
  origin_load_target
87
87
  end
88
+
89
+ alias_method :origin_empty?, :empty?
90
+ def empty?
91
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
92
+ origin_empty?
93
+ end
88
94
  end
89
95
 
90
96
  ::ActiveRecord::Associations::SingularAssociation.class_eval do
@@ -92,22 +98,12 @@ module Bullet
92
98
  alias_method :origin_reader, :reader
93
99
  def reader(force_reload = false)
94
100
  result = origin_reader(force_reload)
95
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
101
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
96
102
  Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
97
103
  result
98
104
  end
99
105
  end
100
106
 
101
- ::ActiveRecord::Associations::Association.class_eval do
102
- alias_method :origin_set_inverse_instance, :set_inverse_instance
103
- def set_inverse_instance(record)
104
- if record && invertible_for?(record)
105
- Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
106
- end
107
- origin_set_inverse_instance(record)
108
- end
109
- end
110
-
111
107
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
112
108
  alias_method :origin_has_cached_counter?, :has_cached_counter?
113
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)
@@ -86,6 +87,12 @@ module Bullet
86
87
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
87
88
  origin_load_target
88
89
  end
90
+
91
+ alias_method :origin_empty?, :empty?
92
+ def empty?
93
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
94
+ origin_empty?
95
+ end
89
96
  end
90
97
 
91
98
  ::ActiveRecord::Associations::SingularAssociation.class_eval do
@@ -5,17 +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.primary_key_value
8
9
 
9
- Bullet.debug("Detector::Association#add_object_associations", "object: #{object.bullet_ar_key}, associations: #{associations}")
10
- 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)
11
12
  end
12
13
 
13
14
  def add_call_object_associations(object, associations)
14
15
  return unless Bullet.start?
15
16
  return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
17
+ return unless object.primary_key_value
16
18
 
17
- Bullet.debug("Detector::Association#add_call_object_associations", "object: #{object.bullet_ar_key}, associations: #{associations}")
18
- 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)
19
21
  end
20
22
 
21
23
  private
@@ -46,13 +48,19 @@ module Bullet
46
48
  # impossible_objects keep the class to objects relationships
47
49
  # that the objects may not cause N+1 query.
48
50
  # e.g. { Post => ["Post:1", "Post:2"] }
49
- # Notice: impossible_objects are not accurate,
50
51
  # if find collection returns only one object, then the object is impossible object,
51
52
  # impossible_objects are used to avoid treating 1+1 query to N+1 query.
52
53
  def impossible_objects
53
54
  Thread.current[:bullet_impossible_objects]
54
55
  end
55
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
+
56
64
  # eager_loadings keep the object relationships
57
65
  # that the associations are preloaded by find :include.
58
66
  # e.g. { ["Post:1", "Post:2"] => [:comments, :user] }
@@ -5,9 +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.primary_key_value
8
9
 
9
- Bullet.debug("Detector::CounterCache#add_counter_cache", "object: #{object.bullet_ar_key}, associations: #{associations}")
10
- 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)
11
12
  create_notification object.class.to_s, associations
12
13
  end
13
14
  end
@@ -15,18 +16,20 @@ module Bullet
15
16
  def add_possible_objects(object_or_objects)
16
17
  return unless Bullet.start?
17
18
  return unless Bullet.counter_cache_enable?
18
-
19
19
  objects = Array(object_or_objects)
20
- Bullet.debug("Detector::CounterCache#add_possible_objects", "objects: #{objects.map(&:bullet_ar_key).join(', ')}")
21
- objects.each { |object| possible_objects.add object.bullet_ar_key }
20
+ return if objects.map(&:primary_key_value).compact.empty?
21
+
22
+ Bullet.debug("Detector::CounterCache#add_possible_objects", "objects: #{objects.map(&:bullet_key).join(', ')}")
23
+ objects.each { |object| possible_objects.add object.bullet_key }
22
24
  end
23
25
 
24
26
  def add_impossible_object(object)
25
27
  return unless Bullet.start?
26
28
  return unless Bullet.counter_cache_enable?
29
+ return unless object.primary_key_value
27
30
 
28
- Bullet.debug("Detector::CounterCache#add_impossible_object", "object: #{object.bullet_ar_key}")
29
- 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
30
33
  end
31
34
 
32
35
  private
@@ -47,8 +50,8 @@ module Bullet
47
50
  Thread.current[:bullet_counter_impossible_objects]
48
51
  end
49
52
 
50
- def conditions_met?(bullet_ar_key, associations)
51
- 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)
52
55
  end
53
56
  end
54
57
  end