bullet 4.0.0 → 4.13.1

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 (112) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -1
  4. data/.travis.yml +17 -6
  5. data/CHANGELOG.md +86 -0
  6. data/Gemfile +13 -12
  7. data/Gemfile.mongoid +14 -0
  8. data/Gemfile.mongoid-2.4 +19 -0
  9. data/Gemfile.mongoid-2.5 +19 -0
  10. data/Gemfile.mongoid-2.6 +19 -0
  11. data/Gemfile.mongoid-2.7 +19 -0
  12. data/Gemfile.mongoid-2.8 +19 -0
  13. data/Gemfile.mongoid-3.0 +19 -0
  14. data/Gemfile.mongoid-3.1 +19 -0
  15. data/Gemfile.mongoid-4.0 +19 -0
  16. data/Gemfile.rails-3.0 +19 -0
  17. data/Gemfile.rails-3.1 +19 -0
  18. data/Gemfile.rails-3.2 +19 -0
  19. data/Gemfile.rails-4.0 +19 -0
  20. data/Gemfile.rails-4.1 +19 -0
  21. data/{Hacking.textile → Hacking.md} +10 -5
  22. data/README.md +432 -0
  23. data/Rakefile +13 -6
  24. data/bullet.gemspec +6 -3
  25. data/lib/bullet/active_record3.rb +49 -11
  26. data/lib/bullet/active_record3x.rb +134 -0
  27. data/lib/bullet/{active_record31.rb → active_record4.rb} +45 -15
  28. data/lib/bullet/active_record41.rb +128 -0
  29. data/lib/bullet/dependency.rb +81 -0
  30. data/lib/bullet/detector/association.rb +24 -68
  31. data/lib/bullet/detector/base.rb +0 -6
  32. data/lib/bullet/detector/counter_cache.rb +59 -0
  33. data/lib/bullet/detector/n_plus_one_query.rb +56 -15
  34. data/lib/bullet/detector/unused_eager_loading.rb +84 -0
  35. data/lib/bullet/detector.rb +2 -2
  36. data/lib/bullet/ext/object.rb +10 -2
  37. data/lib/bullet/{mongoid.rb → mongoid2x.rb} +18 -18
  38. data/lib/bullet/mongoid3x.rb +56 -0
  39. data/lib/bullet/mongoid4x.rb +56 -0
  40. data/lib/bullet/notification/base.rb +22 -4
  41. data/lib/bullet/notification/n_plus_one_query.rb +1 -1
  42. data/lib/bullet/notification.rb +2 -0
  43. data/lib/bullet/rack.rb +51 -17
  44. data/lib/bullet/registry/base.rb +1 -1
  45. data/lib/bullet/registry/object.rb +4 -4
  46. data/lib/bullet/version.rb +1 -2
  47. data/lib/bullet.rb +119 -39
  48. data/perf/benchmark.rb +1 -4
  49. data/spec/bullet/detector/association_spec.rb +2 -70
  50. data/spec/bullet/detector/base_spec.rb +0 -6
  51. data/spec/bullet/detector/counter_cache_spec.rb +56 -0
  52. data/spec/bullet/detector/n_plus_one_query_spec.rb +78 -34
  53. data/spec/bullet/detector/unused_eager_loading_spec.rb +88 -0
  54. data/spec/bullet/ext/object_spec.rb +18 -7
  55. data/spec/bullet/ext/string_spec.rb +2 -2
  56. data/spec/bullet/notification/base_spec.rb +68 -15
  57. data/spec/bullet/notification/counter_cache_spec.rb +2 -2
  58. data/spec/bullet/notification/n_plus_one_query_spec.rb +4 -3
  59. data/spec/bullet/notification/unused_eager_loading_spec.rb +2 -2
  60. data/spec/bullet/notification_collector_spec.rb +4 -4
  61. data/spec/bullet/rack_spec.rb +40 -39
  62. data/spec/bullet/registry/association_spec.rb +3 -3
  63. data/spec/bullet/registry/base_spec.rb +6 -6
  64. data/spec/bullet/registry/object_spec.rb +4 -5
  65. data/spec/bullet_spec.rb +41 -0
  66. data/spec/integration/active_record3/association_spec.rb +662 -0
  67. data/spec/integration/active_record4/association_spec.rb +660 -0
  68. data/spec/integration/counter_cache_spec.rb +63 -0
  69. data/spec/integration/mongoid/association_spec.rb +190 -208
  70. data/spec/models/category.rb +1 -1
  71. data/spec/models/client.rb +1 -1
  72. data/spec/models/comment.rb +2 -2
  73. data/spec/models/document.rb +2 -2
  74. data/spec/models/firm.rb +1 -1
  75. data/spec/models/mongoid/address.rb +2 -0
  76. data/spec/models/mongoid/category.rb +2 -0
  77. data/spec/models/mongoid/comment.rb +2 -0
  78. data/spec/models/mongoid/company.rb +2 -0
  79. data/spec/models/mongoid/entry.rb +2 -0
  80. data/spec/models/mongoid/post.rb +4 -0
  81. data/spec/models/mongoid/user.rb +5 -0
  82. data/spec/models/newspaper.rb +1 -1
  83. data/spec/models/pet.rb +1 -1
  84. data/spec/models/post.rb +6 -13
  85. data/spec/spec_helper.rb +60 -25
  86. data/spec/support/bullet_ext.rb +1 -1
  87. data/spec/support/mongo_seed.rb +26 -2
  88. data/spec/support/sqlite_seed.rb +0 -6
  89. data/test.sh +15 -0
  90. metadata +77 -54
  91. data/.rvmrc +0 -2
  92. data/.rvmrc.example +0 -2
  93. data/Gemfile.lock +0 -132
  94. data/Gemfile.rails-2.3.14 +0 -16
  95. data/Gemfile.rails-2.3.14.lock +0 -65
  96. data/Gemfile.rails-3.0.12 +0 -17
  97. data/Gemfile.rails-3.0.12.lock +0 -116
  98. data/Gemfile.rails-3.1.4 +0 -18
  99. data/Gemfile.rails-3.1.4.lock +0 -134
  100. data/README.textile +0 -395
  101. data/README_for_rails2.textile +0 -400
  102. data/lib/bullet/action_controller2.rb +0 -49
  103. data/lib/bullet/active_record2.rb +0 -121
  104. data/lib/bullet/detector/counter.rb +0 -48
  105. data/lib/bullet/detector/unused_eager_association.rb +0 -42
  106. data/spec/bullet/detector/counter_spec.rb +0 -64
  107. data/spec/bullet/detector/unused_eager_association_spec.rb +0 -62
  108. data/spec/integration/association_spec.rb +0 -593
  109. data/spec/integration/counter_spec.rb +0 -39
  110. data/spec/integration/rails2/association_spec.rb +0 -593
  111. data/spec/integration/rails2/counter_spec.rb +0 -39
  112. data/test.result +0 -2293
@@ -1,400 +0,0 @@
1
- h1. Bullet
2
-
3
- The Bullet plugin/gem is designed to help you increase your application's performance by reducing the number of queries it makes. It will watch your queries while you develop your application and notify you when you should add eager loading (N+1 queries), when you're using eager loading that isn't necessary and when you should use counter cache.
4
-
5
- Best practice is to use Bullet in development mode or custom mode (staging, profile, etc.). The last thing you want is your clients getting alerts about how lazy you are.
6
-
7
- The Bullet plugin/gem now supports rails 2.1, 2.2 and 2.3, tested in rails 2.1.2, 2.2.2 and 2.3.2.
8
-
9
- ****************************************************************************
10
-
11
- h2. Change
12
-
13
- There is a large refactor from gem 1.4 to 1.5, so if you upgrade to 1.5 gem, please read the Configuration section again and rewrite your configuration.
14
-
15
- ****************************************************************************
16
-
17
- h2. Contributors
18
-
19
- "https://github.com/flyerhzm/bullet/contributors":https://github.com/flyerhzm/bullet/contributors
20
-
21
- ****************************************************************************
22
-
23
- h2. Install
24
-
25
- You can install it as a gem:
26
- <pre><code>
27
- sudo gem install bullet
28
- </code></pre>
29
-
30
- ****************************************************************************
31
-
32
- h2. Configuration
33
-
34
- Bullet won't do ANYTHING unless you tell it to explicitly. Append to <code>config/environments/development.rb</code> initializer with the following code:
35
- <pre><code>
36
- config.after_initialize do
37
- Bullet.enable = true
38
- Bullet.alert = true
39
- Bullet.bullet_logger = true
40
- Bullet.console = true
41
- Bullet.growl = true
42
- Bullet.rails_logger = true
43
- Bullet.disable_browser_cache = true
44
- Bullet.xmpp = { :account => 'bullets_account@jabber.org',
45
- :password => 'bullets_password_for_jabber',
46
- :receiver => 'your_account@jabber.org',
47
- :show_online_status => true }
48
- end
49
- </code></pre>
50
-
51
- The notifier of bullet is a wrap of "uniform_notifier":https://github.com/flyerhzm/uniform_notifier
52
-
53
- The code above will enable all five of the Bullet notification systems:
54
- * <code>Bullet.enable</code>: enable Bullet plugin/gem, otherwise do nothing
55
- * <code>Bullet.alert</code>: pop up a JavaScript alert in the browser
56
- * <code>Bullet.bullet_logger</code>: log to the Bullet log file (RAILS_ROOT/log/bullet.log)
57
- * <code>Bullet.rails_logger</code>: add warnings directly to the Rails log
58
- * <code>Bullet.console</code>: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
59
- * <code>Bullet.growl</code>: pop up Growl warnings if your system has Growl installed. Requires a little bit of configuration
60
- * <code>Bullet.disable_browser_cache</code>: disable browser cache which usually causes unexpected problems
61
-
62
- ****************************************************************************
63
-
64
- h2. Log
65
-
66
- The Bullet log <code>log/bullet.log</code> will look something like this:
67
-
68
- * N+1 Query:
69
- <pre><code>
70
- 2009-08-25 20:40:17[INFO] N+1 Query: PATH_INFO: /posts; model: Post => associations: [comments]·
71
- Add to your finder: :include => [:comments]
72
- 2009-08-25 20:40:17[INFO] N+1 Query: method call stack:·
73
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:11:in `_run_erb_app47views47posts47index46html46erb'
74
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
75
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `_run_erb_app47views47posts47index46html46erb'
76
- /Users/richard/Downloads/test/app/controllers/posts_controller.rb:7:in `index'
77
- </code></pre>
78
-
79
- The first two lines are notifications that N+1 queries have been encountered. The remaining lines are stack traces so you can find exactly where the queries were invoked in your code, and fix them.
80
-
81
- * Unused eager loading:
82
- <pre><code>
83
- 2009-08-25 20:53:56[INFO] Unused eager loadings: PATH_INFO: /posts; model: Post => associations: [comments]·
84
- Remove from your finder: :include => [:comments]
85
- </code></pre>
86
-
87
- These two lines are notifications that unused eager loadings have been encountered.
88
-
89
- * Need counter cache:
90
- <pre><code>
91
- 2009-09-11 09:46:50[INFO] Need Counter Cache
92
- Post => [:comments]
93
- </code></pre>
94
-
95
- ****************************************************************************
96
-
97
- h2. Growl Support
98
-
99
- To get Growl support up-and-running for Bullet, follow the steps below:
100
- * Install the ruby-growl gem: <code>gem install ruby-growl</code>
101
- * Open the Growl preference pane in Systems Preferences
102
- * Click the "Network" tab
103
- * Make sure both "Listen for incoming notifications" and "Allow remote application registration" are checked. *Note*: If you set a password, you will need to set <code>Bullet.growl = { :password => 'growl password' }</code> in the config file.
104
- * Restart Growl ("General" tab -> Stop Growl -> Start Growl)
105
- * Boot up your application. Bullet will automatically send a Growl notification when Growl is turned on. If you do not see it when your application loads, make sure it is enabled in your initializer and double-check the steps above.
106
-
107
- ****************************************************************************
108
-
109
- h2. Ruby 1.9 issue
110
-
111
- ruby-growl gem has an issue about md5 in ruby 1.9, if you use growl and ruby 1.9, check this gist http://gist.github.com/300184
112
-
113
- ****************************************************************************
114
-
115
- h2. XMPP/Jabber Support
116
-
117
- To get XMPP support up-and-running for Bullet, follow the steps below:
118
- * Install the xmpp4r gem: <code>sudo gem install xmpp4r</code>
119
- * Make both the bullet and the receipient account add each other as contacts.
120
- This will require you to manually log into both accounts, add each other
121
- as contact and confirm each others contact request.
122
- * Boot up your application. Bullet will automatically send an XMPP notification when XMPP is turned on.
123
-
124
- ****************************************************************************
125
-
126
- h2. Important
127
-
128
- If you encounter the following errors in development environment:
129
-
130
- <pre><code>
131
- You might have expected an instance of Array.
132
- The error occurred while evaluating nil.include?
133
- /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:142:in `create_time_zone_conversion_attribute?'
134
- /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:75:in `define_attribute_methods'
135
- /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:71:in `each'
136
- /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:71:in `define_attribute_methods'
137
- /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:242:in `method_missing'
138
- </code></pre>
139
-
140
- Or any strange behavior of bullet plugin/gem, *please disable your browser's cache*.
141
-
142
- ****************************************************************************
143
-
144
- h2. Advance
145
-
146
- The bullet plugin/gem use rack middleware for http request. If you want to bullet for without http server, such as job server. You can do like this:
147
-
148
- <pre><code>
149
- Bullet.start_request if Bullet.enable?
150
- # run job
151
- if Bullet.enable?
152
- Bullet.growl_notification
153
- Bullet.log_notification('JobServer: ')
154
- Bullet.end_request
155
- end
156
- </code></pre>
157
-
158
- Or you want to use it in test mode
159
-
160
- <pre><code>
161
- before(:each)
162
- Bullet.start_request if Bullet.enable?
163
- end
164
-
165
- after(:each)
166
- if Bullet.enable?
167
- Bullet.perform_out_of_channel_notifications
168
- Bullet.end_request
169
- end
170
- end
171
- </code></pre>
172
-
173
- Don't forget enabling bullet in test environment.
174
-
175
- ****************************************************************************
176
-
177
- h2. Links
178
-
179
- * "http://weblog.rubyonrails.org/2009/10/22/community-highlights":http://weblog.rubyonrails.org/2009/10/22/community-highlights
180
- * "http://ruby5.envylabs.com/episodes/9-episode-8-september-8-2009":http://ruby5.envylabs.com/episodes/9-episode-8-september-8-2009
181
- * "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
182
-
183
- ****************************************************************************
184
-
185
- h2. Step by step example
186
-
187
- 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.
188
-
189
- 1. setup test environment
190
-
191
- <pre><code>
192
- $ rails test_bullet
193
- $ cd test_bullet
194
- $ script/generate scaffold post name:string
195
- $ script/generate scaffold comment name:string post_id:integer
196
- $ rake db:migrate
197
- </code></pre>
198
-
199
- 2. change <code>app/model/post.rb</code> and <code>app/model/comment.rb</code>
200
-
201
- <pre><code>
202
- class Post < ActiveRecord::Base
203
- has_many :comments
204
- end
205
-
206
- class Comment < ActiveRecord::Base
207
- belongs_to :post
208
- end
209
- </code></pre>
210
-
211
- 3. go to script/console and execute
212
-
213
- <pre><code>
214
- post1 = Post.create(:name => 'first')
215
- post2 = Post.create(:name => 'second')
216
- post1.comments.create(:name => 'first')
217
- post1.comments.create(:name => 'second')
218
- post2.comments.create(:name => 'third')
219
- post2.comments.create(:name => 'fourth')
220
- </code></pre>
221
-
222
- 4. change the <code>app/views/posts/index.html.erb</code> to produce a N+1 query
223
-
224
- <pre><code>
225
- <% @posts.each do |post| %>
226
- <tr>
227
- <td><%=h post.name %></td>
228
- <td><%= post.comments.collect(&:name) %></td>
229
- <td><%= link_to 'Show', post %></td>
230
- <td><%= link_to 'Edit', edit_post_path(post) %></td>
231
- <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
232
- </tr>
233
- <% end %>
234
- </code></pre>
235
-
236
- 5. add bullet plugin
237
-
238
- <pre><code>
239
- $ script/plugin install git://github.com/flyerhzm/bullet.git
240
- </code></pre>
241
-
242
- 6. enable the bullet plugin in development, add a line to <code>config/environments/development.rb</code>
243
-
244
- <pre><code>
245
- config.after_initialize do
246
- Bullet.enable = true
247
- Bullet.alert = true
248
- Bullet.bullet_logger = true
249
- Bullet.console = true
250
- # Bullet.growl = true
251
- Bullet.rails_logger = true
252
- Bullet.disable_browser_cache = true
253
- end
254
- </code></pre>
255
-
256
- 7. start server
257
-
258
- <pre><code>
259
- $ script/server
260
- </code></pre>
261
-
262
- 8. input http://localhost:3000/posts in browser, then you will see a popup alert box says
263
-
264
- <pre><code>
265
- The request has unused preload associations as follows:
266
- None
267
- The request has N+1 queries as follows:
268
- model: Post => associations: [comment]
269
- </code></pre>
270
-
271
- which means there is a N+1 query from post object to comments associations.
272
-
273
- In the meanwhile, there's a log appended into <code>log/bullet.log</code> file
274
-
275
- <pre><code>
276
- 2009-08-20 09:12:19[INFO] N+1 Query: PATH_INFO: /posts; model: Post => assocations: [comments]
277
- Add your finder: :include => [:comments]
278
- 2009-08-20 09:12:19[INFO] N+1 Query: method call stack:
279
- /Users/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:11:in `_run_erb_app47views47posts47index46html46erb'
280
- /Users/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:8:in `each'
281
- /Users/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:8:in `_run_erb_app47views47posts47index46html46erb'
282
- /Users/flyerhzm/Downloads/test_bullet/app/controllers/posts_controller.rb:7:in `index'
283
- </code></pre>
284
-
285
- The generated SQLs are
286
-
287
- <pre><code>
288
- Post Load (1.0ms) SELECT * FROM "posts"
289
- Comment Load (0.4ms) SELECT * FROM "comments" WHERE ("comments".post_id = 1)
290
- Comment Load (0.3ms) SELECT * FROM "comments" WHERE ("comments".post_id = 2)
291
- </code></pre>
292
-
293
-
294
- 9. fix the N+1 query, change <code>app/controllers/posts_controller.rb</code> file
295
-
296
- <pre><code>
297
- def index
298
- @posts = Post.find(:all, :include => :comments)
299
-
300
- respond_to do |format|
301
- format.html # index.html.erb
302
- format.xml { render :xml => @posts }
303
- end
304
- end
305
- </code></pre>
306
-
307
- 10. refresh http://localhost:3000/posts page, no alert box and no log appended.
308
-
309
- The generated SQLs are
310
-
311
- <pre><code>
312
- Post Load (0.5ms) SELECT * FROM "posts"
313
- Comment Load (0.5ms) SELECT "comments".* FROM "comments" WHERE ("comments".post_id IN (1,2))
314
- </code></pre>
315
-
316
- a N+1 query fixed. Cool!
317
-
318
- 11. now simulate unused eager loading. Change <code>app/controllers/posts_controller.rb</code> and <code>app/views/posts/index.html.erb</code>
319
-
320
- <pre><code>
321
- def index
322
- @posts = Post.find(:all, :include => :comments)
323
-
324
- respond_to do |format|
325
- format.html # index.html.erb
326
- format.xml { render :xml => @posts }
327
- end
328
- end
329
- </code></pre>
330
-
331
- <pre><code>
332
- <% @posts.each do |post| %>
333
- <tr>
334
- <td><%=h post.name %></td>
335
- <td><%= link_to 'Show', post %></td>
336
- <td><%= link_to 'Edit', edit_post_path(post) %></td>
337
- <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
338
- </tr>
339
- <% end %>
340
- </code></pre>
341
-
342
- 12. refresh http://localhost:3000/posts page, then you will see a popup alert box says
343
-
344
- <pre><code>
345
- The request has unused preload associations as follows:
346
- model: Post => associations: [comment]
347
- The request has N+1 queries as follows:
348
- None
349
- </code></pre>
350
-
351
- In the meanwhile, there's a log appended into <code>log/bullet.log</code> file
352
-
353
- <pre><code>
354
- 2009-08-25 21:13:22[INFO] Unused preload associations: PATH_INFO: /posts; model: Post => associations: [comments]·
355
- Remove from your finder: :include => [:comments]
356
- </code></pre>
357
-
358
- 13. simulate counter_cache. Change <code>app/controllers/posts_controller.rb</code> and <code>app/views/posts/index.html.erb</code>
359
-
360
- <pre><code>
361
- def index
362
- @posts = Post.find(:all)
363
-
364
- respond_to do |format|
365
- format.html # index.html.erb
366
- format.xml { render :xml => @posts }
367
- end
368
- end
369
- </code></pre>
370
-
371
- <pre><code>
372
- <% @posts.each do |post| %>
373
- <tr>
374
- <td><%=h post.name %></td>
375
- <td><%=h post.comments.size %></td>
376
- <td><%= link_to 'Show', post %></td>
377
- <td><%= link_to 'Edit', edit_post_path(post) %></td>
378
- <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
379
- </tr>
380
- <% end %>
381
- </code></pre>
382
-
383
- 14. refresh http://localhost:3000/posts page, then you will see a popup alert box says
384
-
385
- <pre><code>
386
- Need counter cache
387
- Post => [:comments]
388
- </code></pre>
389
-
390
- In the meanwhile, there's a log appended into <code>log/bullet.log</code> file.
391
-
392
- <pre><code>
393
- 2009-09-11 10:07:10[INFO] Need Counter Cache
394
- Post => [:comments]
395
- </code></pre>
396
-
397
- ****************************************************************************
398
-
399
-
400
- Copyright (c) 2009 - 2012 Richard Huang (flyerhzm@gmail.com), released under the MIT license
@@ -1,49 +0,0 @@
1
- module Bullet
2
- class ActionController
3
- def self.enable
4
- require 'action_controller'
5
- if Rails.version =~ /\A2.3/
6
- ::ActionController::Dispatcher.middleware.use Bullet::Rack
7
- ::ActionController::Dispatcher.class_eval do
8
- class <<self
9
- alias_method :origin_reload_application, :reload_application
10
- def reload_application
11
- origin_reload_application
12
- Bullet.clear
13
- end
14
- end
15
- end
16
- elsif Rails.version =~ /\A2.[12]/
17
- ::ActionController::Dispatcher.class_eval do
18
- alias_method :origin_reload_application, :reload_application
19
- def reload_application
20
- origin_reload_application
21
- Bullet.clear
22
- end
23
- end
24
-
25
- ::ActionController::Base.class_eval do
26
- alias_method :origin_process, :process
27
- def process(request, response, method = :perform_action, *arguments)
28
- Bullet.start_request
29
- response = origin_process(request, response, method = :perform_action, *arguments)
30
-
31
- if Bullet.notification?
32
- if response.headers["type"] && response.headers["type"].include?('text/html') &&
33
- response.body.include?("<html>") && response.body.include?("</html>")
34
- response.body <<= Bullet.gather_inline_notifications
35
- response.headers["Content-Length"] = response.body.length.to_s
36
- end
37
-
38
- Bullet.perform_out_of_channel_notifications
39
- end
40
- Bullet.end_request
41
- response
42
- end
43
- end
44
- else
45
- puts "Gem Bullet: Unsupported rails version"
46
- end
47
- end
48
- end
49
- end
@@ -1,121 +0,0 @@
1
- module Bullet
2
- module ActiveRecord
3
- def self.enable
4
- require 'active_record'
5
- ::ActiveRecord::Base.class_eval do
6
- class << self
7
- alias_method :origin_find_every, :find_every
8
- # if select a collection of objects, then these objects have possible to cause N+1 query.
9
- # if select only one object, then the only one object has impossible to cause N+1 query.
10
- def find_every(options)
11
- records = origin_find_every(options)
12
-
13
- if records
14
- if records.size > 1
15
- Bullet::Detector::Association.add_possible_objects(records)
16
- Bullet::Detector::Counter.add_possible_objects(records)
17
- elsif records.size == 1
18
- Bullet::Detector::Association.add_impossible_object(records.first)
19
- Bullet::Detector::Counter.add_impossible_object(records.first)
20
- end
21
- end
22
-
23
- records
24
- end
25
- end
26
- end
27
-
28
- ::ActiveRecord::AssociationPreload::ClassMethods.class_eval do
29
- alias_method :origin_preload_associations, :preload_associations
30
- # include query for one to many associations.
31
- # keep this eager loadings.
32
- def preload_associations(records, associations, preload_options={})
33
- records = [records].flatten.compact.uniq
34
- return if records.empty?
35
- records.each do |record|
36
- Bullet::Detector::Association.add_object_associations(record, associations)
37
- end
38
- Bullet::Detector::Association.add_eager_loadings(records, associations)
39
- origin_preload_associations(records, associations, preload_options={})
40
- end
41
- end
42
-
43
- ::ActiveRecord::Associations::ClassMethods.class_eval do
44
- # add include in named_scope
45
- alias_method :origin_find_with_associations, :find_with_associations
46
- def find_with_associations(options)
47
- records = origin_find_with_associations(options)
48
- associations = merge_includes(scope(:find, :include), options[:include])
49
- records.each do |record|
50
- Bullet::Detector::Association.add_object_associations(record, associations)
51
- Bullet::Detector::NPlusOneQuery.call_association(record, associations)
52
- end
53
- Bullet::Detector::Association.add_eager_loadings(records, associations)
54
- records
55
- end
56
- end
57
-
58
- ::ActiveRecord::Associations::ClassMethods::JoinDependency.class_eval do
59
- # call join associations
60
- alias_method :origin_construct_association, :construct_association
61
- def construct_association(record, join, row)
62
- associations = join.reflection.name
63
- Bullet::Detector::Association.add_object_associations(record, associations)
64
- Bullet::Detector::NPlusOneQuery.call_association(record, associations)
65
- origin_construct_association(record, join, row)
66
- end
67
- end
68
-
69
- ::ActiveRecord::Associations::AssociationCollection.class_eval do
70
- # call one to many associations
71
- alias_method :origin_load_target, :load_target
72
- def load_target
73
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
74
- origin_load_target
75
- end
76
-
77
- alias_method :origin_first, :first
78
- def first(*args)
79
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
80
- origin_first(*args)
81
- end
82
-
83
- alias_method :origin_last, :last
84
- def last(*args)
85
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
86
- origin_last(*args)
87
- end
88
- end
89
-
90
- ::ActiveRecord::Associations::AssociationProxy.class_eval do
91
- # call has_one and belong_to association
92
- alias_method :origin_load_target, :load_target
93
- def load_target
94
- # avoid stack level too deep
95
- result = origin_load_target
96
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? {|c| c.include?("load_target") }
97
- Bullet::Detector::Association.add_possible_objects(result)
98
- result
99
- end
100
- end
101
-
102
- ::ActiveRecord::Associations::HasManyAssociation.class_eval do
103
- alias_method :origin_has_cached_counter?, :has_cached_counter?
104
- def has_cached_counter?
105
- result = origin_has_cached_counter?
106
- Bullet::Detector::Counter.add_counter_cache(@owner, @reflection.name) unless result
107
- result
108
- end
109
- end
110
-
111
- ::ActiveRecord::Associations::HasManyThroughAssociation.class_eval do
112
- alias_method :origin_has_cached_counter?, :has_cached_counter?
113
- def has_cached_counter?
114
- result = origin_has_cached_counter?
115
- Bullet::Detector::Counter.add_counter_cache(@owner, @reflection.name) unless result
116
- result
117
- end
118
- end
119
- end
120
- end
121
- end
@@ -1,48 +0,0 @@
1
- module Bullet
2
- module Detector
3
- class Counter < Base
4
- class <<self
5
- def clear
6
- @@possible_objects = nil
7
- @@impossible_objects = nil
8
- end
9
-
10
- def add_counter_cache(object, associations)
11
- if conditions_met?(object.bullet_ar_key, associations)
12
- create_notification object.class.to_s, associations
13
- end
14
- end
15
-
16
- def add_possible_objects(object_or_objects)
17
- if object_or_objects.is_a? Array
18
- object_or_objects.each { |object| possible_objects.add object.bullet_ar_key }
19
- else
20
- possible_objects.add object_or_objects.bullet_ar_key
21
- end
22
- end
23
-
24
- def add_impossible_object(object)
25
- impossible_objects.add object.bullet_ar_key
26
- end
27
-
28
- private
29
- def create_notification(klazz, associations)
30
- notice = Bullet::Notification::CounterCache.new klazz, associations
31
- Bullet.notification_collector.add notice
32
- end
33
-
34
- def possible_objects
35
- @@possible_objects ||= Bullet::Registry::Object.new
36
- end
37
-
38
- def impossible_objects
39
- @@impossible_objects ||= Bullet::Registry::Object.new
40
- end
41
-
42
- def conditions_met?(bullet_ar_key, associations)
43
- possible_objects.include?(bullet_ar_key) && !impossible_objects.include?(bullet_ar_key)
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,42 +0,0 @@
1
- module Bullet
2
- module Detector
3
- class UnusedEagerAssociation < Association
4
- class <<self
5
- # check if there are unused preload associations.
6
- # get related_objects from eager_loadings associated with object and associations
7
- # get call_object_association from associations of call_object_associations whose object is in related_objects
8
- # if association not in call_object_association, then the object => association - call_object_association is ununsed preload assocations
9
- def check_unused_preload_associations
10
- @@checked = true
11
- object_associations.each do |bullet_ar_key, associations|
12
- object_association_diff = diff_object_associations bullet_ar_key, associations
13
- next if object_association_diff.empty?
14
-
15
- create_notification bullet_ar_key.bullet_class_name, object_association_diff
16
- end
17
- end
18
-
19
- private
20
- def create_notification(klazz, associations)
21
- notice = Bullet::Notification::UnusedEagerLoading.new(klazz, associations)
22
- Bullet.notification_collector.add(notice)
23
- end
24
-
25
- def call_associations(bullet_ar_key, associations)
26
- all = Set.new
27
- eager_loadings.similarly_associated(bullet_ar_key, associations).each do |related_bullet_ar_key|
28
- coa = call_object_associations[related_bullet_ar_key]
29
- next if coa.nil?
30
- all.merge coa
31
- end
32
- all.to_a
33
- end
34
-
35
- def diff_object_associations(bullet_ar_key, associations)
36
- potential_associations = associations - call_associations(bullet_ar_key, associations)
37
- potential_associations.reject { |a| a.is_a?(Hash) }
38
- end
39
- end
40
- end
41
- end
42
- end