bullet 1.7.6 → 2.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -4,23 +4,7 @@ The Bullet plugin/gem is designed to help you increase your application's perfor
4
4
 
5
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
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
- *Important: bullet gem has been moved to gemcutter.org*
10
-
11
- ****************************************************************************
12
-
13
- h2. Change
14
-
15
- 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.
16
-
17
- ****************************************************************************
18
-
19
- h2. Contributors
20
-
21
- flipsasser added Growl, console.log and Rails.log support, very awesome. And he also improved README.
22
- rainux added group style console.log.
23
- 2collegebums added some great specs to generate red bar.
7
+ The Bullet plugin/gem now supports rails 2.1, 2.2, 2.3 and 3.0, tested in rails 2.1.2, 2.2.2, 2.3.2 and 3.0.0.beta.
24
8
 
25
9
  ****************************************************************************
26
10
 
@@ -31,13 +15,8 @@ You can add Bullet to your Rails gem requirements:
31
15
 
32
16
  You can install it as a gem:
33
17
  <pre><code>
34
- sudo gem sources -a http://gemcutter.org
35
- sudo gem install bullet
18
+ sudo gem install bullet --pre
36
19
  </code></pre>
37
-
38
- Or you can install it as a rails plugin:
39
- <pre><code>script/plugin install git://github.com/flyerhzm/bullet.git</code></pre>
40
-
41
20
  ****************************************************************************
42
21
 
43
22
  h2. Configuration
@@ -67,7 +46,7 @@ It is recommended to config growl notification as follows if your collaborators
67
46
  The code above will enable all five of the Bullet notification systems:
68
47
  * <code>Bullet.enable</code>: enable Bullet plugin/gem, otherwise do nothing
69
48
  * <code>Bullet.alert</code>: pop up a JavaScript alert in the browser
70
- * <code>Bullet.bullet_logger</code>: log to the Bullet log file (RAILS_ROOT/log/bullet.log)
49
+ * <code>Bullet.bullet_logger</code>: log to the Bullet log file (Rails.root/log/bullet.log)
71
50
  * <code>Bullet.rails_logger</code>: add warnings directly to the Rails log
72
51
  * <code>Bullet.console</code>: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
73
52
  * <code>Bullet.growl</code>: pop up Growl warnings if your system has Growl installed. Requires a little bit of configuration
@@ -186,6 +165,14 @@ h2. Links
186
165
 
187
166
  ****************************************************************************
188
167
 
168
+ h2. Contributors
169
+
170
+ flipsasser added Growl, console.log and Rails.log support, very awesome. And he also improved README.
171
+ rainux added group style console.log.
172
+ 2collegebums added some great specs to generate red bar.
173
+
174
+ ****************************************************************************
175
+
189
176
  h2. Step by step example
190
177
 
191
178
  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.
@@ -195,8 +182,8 @@ Bullet is designed to function as you browse through your application in develop
195
182
  <pre><code>
196
183
  $ rails test
197
184
  $ cd test
198
- $ script/generate scaffold post name:string
199
- $ script/generate scaffold comment name:string post_id:integer
185
+ $ script/rails g scaffold post name:string
186
+ $ script/rails g scaffold comment name:string post_id:integer
200
187
  $ rake db:migrate
201
188
  </code></pre>
202
189
 
@@ -212,7 +199,7 @@ class Comment < ActiveRecord::Base
212
199
  end
213
200
  </code></pre>
214
201
 
215
- 3. go to script/console and execute
202
+ 3. go to <code>script/rails c</code> and execute
216
203
 
217
204
  <pre><code>
218
205
  post1 = Post.create(:name => 'first')
@@ -260,7 +247,7 @@ end
260
247
  7. start server
261
248
 
262
249
  <pre><code>
263
- $ script/server
250
+ $ script/rails s
264
251
  </code></pre>
265
252
 
266
253
  8. input http://localhost:3000/posts in browser, then you will see a popup alert box says
@@ -299,7 +286,7 @@ The generated SQLs are
299
286
 
300
287
  <pre><code>
301
288
  def index
302
- @posts = Post.find(:all, :include => :comments)
289
+ @posts = Post.includes(:comments)
303
290
 
304
291
  respond_to do |format|
305
292
  format.html # index.html.erb
@@ -323,7 +310,7 @@ a N+1 query fixed. Cool!
323
310
 
324
311
  <pre><code>
325
312
  def index
326
- @posts = Post.find(:all, :include => :comments)
313
+ @posts = Post.includes(:comments)
327
314
 
328
315
  respond_to do |format|
329
316
  format.html # index.html.erb
@@ -0,0 +1,404 @@
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
+ *Important: bullet gem has been moved to gemcutter.org*
10
+
11
+ ****************************************************************************
12
+
13
+ h2. Change
14
+
15
+ 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.
16
+
17
+ ****************************************************************************
18
+
19
+ h2. Contributors
20
+
21
+ flipsasser added Growl, console.log and Rails.log support, very awesome. And he also improved README.
22
+ rainux added group style console.log.
23
+ 2collegebums added some great specs to generate red bar.
24
+
25
+ ****************************************************************************
26
+
27
+ h2. Install
28
+
29
+ You can add Bullet to your Rails gem requirements:
30
+ <pre><code>config.gem 'bullet', :source => 'http://gemcutter.org'</code></pre>
31
+
32
+ You can install it as a gem:
33
+ <pre><code>
34
+ sudo gem sources -a http://gemcutter.org
35
+ sudo gem install bullet
36
+ </code></pre>
37
+
38
+ Or you can install it as a rails plugin:
39
+ <pre><code>script/plugin install git://github.com/flyerhzm/bullet.git</code></pre>
40
+
41
+ ****************************************************************************
42
+
43
+ h2. Configuration
44
+
45
+ Bullet won't do ANYTHING unless you tell it to explicitly. Append to <code>config/environments/development.rb</code> initializer with the following code:
46
+ <pre><code>
47
+ config.after_initialize do
48
+ Bullet.enable = true
49
+ Bullet.alert = true
50
+ Bullet.bullet_logger = true
51
+ Bullet.console = true
52
+ Bullet.growl = true
53
+ Bullet.rails_logger = true
54
+ Bullet.disable_browser_cache = true
55
+ end
56
+ </code></pre>
57
+
58
+ It is recommended to config growl notification as follows if your collaborators are not using MacOS
59
+ <pre><code>
60
+ begin
61
+ require 'ruby-growl'
62
+ Bullet.growl = true
63
+ rescue MissingSourceFile
64
+ end
65
+ </code></pre>
66
+
67
+ The code above will enable all five of the Bullet notification systems:
68
+ * <code>Bullet.enable</code>: enable Bullet plugin/gem, otherwise do nothing
69
+ * <code>Bullet.alert</code>: pop up a JavaScript alert in the browser
70
+ * <code>Bullet.bullet_logger</code>: log to the Bullet log file (RAILS_ROOT/log/bullet.log)
71
+ * <code>Bullet.rails_logger</code>: add warnings directly to the Rails log
72
+ * <code>Bullet.console</code>: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
73
+ * <code>Bullet.growl</code>: pop up Growl warnings if your system has Growl installed. Requires a little bit of configuration
74
+ * <code>Bullet.disable_browser_cache</code>: disable browser cache which usually causes unexpected problems
75
+
76
+ ****************************************************************************
77
+
78
+ h2. Log
79
+
80
+ The Bullet log <code>log/bullet.log</code> will look something like this:
81
+
82
+ * N+1 Query:
83
+ <pre><code>
84
+ 2009-08-25 20:40:17[INFO] N+1 Query: PATH_INFO: /posts; model: Post => associations: [comments]·
85
+ Add to your finder: :include => [:comments]
86
+ 2009-08-25 20:40:17[INFO] N+1 Query: method call stack:·
87
+ /Users/richard/Downloads/test/app/views/posts/index.html.erb:11:in `_run_erb_app47views47posts47index46html46erb'
88
+ /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
89
+ /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `_run_erb_app47views47posts47index46html46erb'
90
+ /Users/richard/Downloads/test/app/controllers/posts_controller.rb:7:in `index'
91
+ </code></pre>
92
+
93
+ 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.
94
+
95
+ * Unused eager loading:
96
+ <pre><code>
97
+ 2009-08-25 20:53:56[INFO] Unused eager loadings: PATH_INFO: /posts; model: Post => associations: [comments]·
98
+ Remove from your finder: :include => [:comments]
99
+ </code></pre>
100
+
101
+ These two lines are notifications that unused eager loadings have been encountered.
102
+
103
+ * Need counter cache:
104
+ <pre><code>
105
+ 2009-09-11 09:46:50[INFO] Need Counter Cache
106
+ Post => [:comments]
107
+ </code></pre>
108
+
109
+ ****************************************************************************
110
+
111
+ h2. Growl Support
112
+
113
+ To get Growl support up-and-running for Bullet, follow the steps below:
114
+ * Install the ruby-growl gem: <code>sudo gem install ruby-growl</code>
115
+ * Open the Growl preference pane in Systems Preferences
116
+ * Click the "Network" tab
117
+ * 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 = 'your_growl_password</code>' in the config file.
118
+ * Restart Growl ("General" tab -> Stop Growl -> Start Growl)
119
+ * 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.
120
+
121
+ ****************************************************************************
122
+
123
+ h2. Ruby 1.9 issue
124
+
125
+ 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
126
+
127
+ ****************************************************************************
128
+
129
+ h2. Important
130
+
131
+ If you encounter the following errors in development environment:
132
+
133
+ <pre><code>
134
+ You might have expected an instance of Array.
135
+ The error occurred while evaluating nil.include?
136
+ /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:142:in `create_time_zone_conversion_attribute?'
137
+ /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:75:in `define_attribute_methods'
138
+ /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:71:in `each'
139
+ /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:71:in `define_attribute_methods'
140
+ /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:242:in `method_missing'
141
+ </code></pre>
142
+
143
+ Or any strange behavior of bullet plugin/gem, *please disable your browser's cache*.
144
+
145
+ ****************************************************************************
146
+
147
+ h2. Advance
148
+
149
+ 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:
150
+
151
+ <pre><code>
152
+ Bullet.start_request if Bullet.enable?
153
+ # run job
154
+ if Bullet.enable?
155
+ Bullet.growl_notification
156
+ Bullet.log_notification('JobServer: ')
157
+ Bullet.end_request
158
+ end
159
+ </code></pre>
160
+
161
+ Or you want to use it in test mode
162
+
163
+ <pre><code>
164
+ before(:each)
165
+ Bullet.start_request if Bullet.enable?
166
+ end
167
+
168
+ after(:each)
169
+ if Bullet.enable?
170
+ Bullet.growl_notification
171
+ Bullet.log_notification('Test: ')
172
+ Bullet.end_request
173
+ end
174
+ end
175
+ </code></pre>
176
+
177
+ Don't forget enabling bullet in test environment.
178
+
179
+ ****************************************************************************
180
+
181
+ h2. Links
182
+
183
+ * "http://weblog.rubyonrails.org/2009/10/22/community-highlights":http://weblog.rubyonrails.org/2009/10/22/community-highlights
184
+ * "http://ruby5.envylabs.com/episodes/9-episode-8-september-8-2009":http://ruby5.envylabs.com/episodes/9-episode-8-september-8-2009
185
+ * "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
186
+
187
+ ****************************************************************************
188
+
189
+ h2. Step by step example
190
+
191
+ 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.
192
+
193
+ 1. setup test environment
194
+
195
+ <pre><code>
196
+ $ rails test
197
+ $ cd test
198
+ $ script/generate scaffold post name:string
199
+ $ script/generate scaffold comment name:string post_id:integer
200
+ $ rake db:migrate
201
+ </code></pre>
202
+
203
+ 2. change <code>app/model/post.rb</code> and <code>app/model/comment.rb</code>
204
+
205
+ <pre><code>
206
+ class Post < ActiveRecord::Base
207
+ has_many :comments
208
+ end
209
+
210
+ class Comment < ActiveRecord::Base
211
+ belongs_to :post
212
+ end
213
+ </code></pre>
214
+
215
+ 3. go to script/console and execute
216
+
217
+ <pre><code>
218
+ post1 = Post.create(:name => 'first')
219
+ post2 = Post.create(:name => 'second')
220
+ post1.comments.create(:name => 'first')
221
+ post1.comments.create(:name => 'second')
222
+ post2.comments.create(:name => 'third')
223
+ post2.comments.create(:name => 'fourth')
224
+ </code></pre>
225
+
226
+ 4. change the <code>app/views/posts/index.html.erb</code> to produce a N+1 query
227
+
228
+ <pre><code>
229
+ <% @posts.each do |post| %>
230
+ <tr>
231
+ <td><%=h post.name %></td>
232
+ <td><%= post.comments.collect(&:name) %></td>
233
+ <td><%= link_to 'Show', post %></td>
234
+ <td><%= link_to 'Edit', edit_post_path(post) %></td>
235
+ <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
236
+ </tr>
237
+ <% end %>
238
+ </code></pre>
239
+
240
+ 5. add bullet plugin
241
+
242
+ <pre><code>
243
+ $ script/plugin install git://github.com/flyerhzm/bullet.git
244
+ </code></pre>
245
+
246
+ 6. enable the bullet plugin in development, add a line to <code>config/environments/development.rb</code>
247
+
248
+ <pre><code>
249
+ config.after_initialize do
250
+ Bullet.enable = true
251
+ Bullet.alert = true
252
+ Bullet.bullet_logger = true
253
+ Bullet.console = true
254
+ # Bullet.growl = true
255
+ Bullet.rails_logger = true
256
+ Bullet.disable_browser_cache = true
257
+ end
258
+ </code></pre>
259
+
260
+ 7. start server
261
+
262
+ <pre><code>
263
+ $ script/server
264
+ </code></pre>
265
+
266
+ 8. input http://localhost:3000/posts in browser, then you will see a popup alert box says
267
+
268
+ <pre><code>
269
+ The request has unused preload associations as follows:
270
+ None
271
+ The request has N+1 queries as follows:
272
+ model: Post => associations: [comment]
273
+ </code></pre>
274
+
275
+ which means there is a N+1 query from post object to comments associations.
276
+
277
+ In the meanwhile, there's a log appended into <code>log/bullet.log</code> file
278
+
279
+ <pre><code>
280
+ 2009-08-20 09:12:19[INFO] N+1 Query: PATH_INFO: /posts; model: Post => assocations: [comments]
281
+ Add your finder: :include => [:comments]
282
+ 2009-08-20 09:12:19[INFO] N+1 Query: method call stack:
283
+ /Users/richard/Downloads/test/app/views/posts/index.html.erb:11:in `_run_erb_app47views47posts47index46html46erb'
284
+ /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
285
+ /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `_run_erb_app47views47posts47index46html46erb'
286
+ /Users/richard/Downloads/test/app/controllers/posts_controller.rb:7:in `index'
287
+ </code></pre>
288
+
289
+ The generated SQLs are
290
+
291
+ <pre><code>
292
+ Post Load (1.0ms) SELECT * FROM "posts"
293
+ Comment Load (0.4ms) SELECT * FROM "comments" WHERE ("comments".post_id = 1)
294
+ Comment Load (0.3ms) SELECT * FROM "comments" WHERE ("comments".post_id = 2)
295
+ </code></pre>
296
+
297
+
298
+ 9. fix the N+1 query, change <code>app/controllers/posts_controller.rb</code> file
299
+
300
+ <pre><code>
301
+ def index
302
+ @posts = Post.find(:all, :include => :comments)
303
+
304
+ respond_to do |format|
305
+ format.html # index.html.erb
306
+ format.xml { render :xml => @posts }
307
+ end
308
+ end
309
+ </code></pre>
310
+
311
+ 10. refresh http://localhost:3000/posts page, no alert box and no log appended.
312
+
313
+ The generated SQLs are
314
+
315
+ <pre><code>
316
+ Post Load (0.5ms) SELECT * FROM "posts"
317
+ Comment Load (0.5ms) SELECT "comments".* FROM "comments" WHERE ("comments".post_id IN (1,2))
318
+ </code></pre>
319
+
320
+ a N+1 query fixed. Cool!
321
+
322
+ 11. now simulate unused eager loading. Change <code>app/controllers/posts_controller.rb</code> and <code>app/views/posts/index.html.erb</code>
323
+
324
+ <pre><code>
325
+ def index
326
+ @posts = Post.find(:all, :include => :comments)
327
+
328
+ respond_to do |format|
329
+ format.html # index.html.erb
330
+ format.xml { render :xml => @posts }
331
+ end
332
+ end
333
+ </code></pre>
334
+
335
+ <pre><code>
336
+ <% @posts.each do |post| %>
337
+ <tr>
338
+ <td><%=h post.name %></td>
339
+ <td><%= link_to 'Show', post %></td>
340
+ <td><%= link_to 'Edit', edit_post_path(post) %></td>
341
+ <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
342
+ </tr>
343
+ <% end %>
344
+ </code></pre>
345
+
346
+ 12. refresh http://localhost:3000/posts page, then you will see a popup alert box says
347
+
348
+ <pre><code>
349
+ The request has unused preload associations as follows:
350
+ model: Post => associations: [comment]
351
+ The request has N+1 queries as follows:
352
+ None
353
+ </code></pre>
354
+
355
+ In the meanwhile, there's a log appended into <code>log/bullet.log</code> file
356
+
357
+ <pre><code>
358
+ 2009-08-25 21:13:22[INFO] Unused preload associations: PATH_INFO: /posts; model: Post => associations: [comments]·
359
+ Remove from your finder: :include => [:comments]
360
+ </code></pre>
361
+
362
+ 13. simulate counter_cache. Change <code>app/controllers/posts_controller.rb</code> and <code>app/views/posts/index.html.erb</code>
363
+
364
+ <pre><code>
365
+ def index
366
+ @posts = Post.find(:all)
367
+
368
+ respond_to do |format|
369
+ format.html # index.html.erb
370
+ format.xml { render :xml => @posts }
371
+ end
372
+ end
373
+ </code></pre>
374
+
375
+ <pre><code>
376
+ <% @posts.each do |post| %>
377
+ <tr>
378
+ <td><%=h post.name %></td>
379
+ <td><%=h post.comments.size %></td>
380
+ <td><%= link_to 'Show', post %></td>
381
+ <td><%= link_to 'Edit', edit_post_path(post) %></td>
382
+ <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
383
+ </tr>
384
+ <% end %>
385
+ </code></pre>
386
+
387
+ 14. refresh http://localhost:3000/posts page, then you will see a popup alert box says
388
+
389
+ <pre><code>
390
+ Need counter cache
391
+ Post => [:comments]
392
+ </code></pre>
393
+
394
+ In the meanwhile, there's a log appended into <code>log/bullet.log</code> file.
395
+
396
+ <pre><code>
397
+ 2009-09-11 10:07:10[INFO] Need Counter Cache
398
+ Post => [:comments]
399
+ </code></pre>
400
+
401
+ ****************************************************************************
402
+
403
+
404
+ Copyright (c) 2009 Richard Huang (flyerhzm@gmail.com), released under the MIT license