Coder Social home page Coder Social logo

bullet's Introduction

Bullet

Main workflow Gem Version AwesomeCode Status for flyerhzm/bullet Coderwall Endorse

The Bullet 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.

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.

Bullet gem now supports activerecord >= 4.0 and mongoid >= 4.0.

If you use activerecord 2.x, please use bullet <= 4.5.0

If you use activerecord 3.x, please use bullet < 5.5.0

External Introduction

Install

You can install it as a gem:

gem install bullet

or add it into a Gemfile (Bundler):

gem 'bullet', group: 'development'

enable the Bullet gem with generate command

bundle exec rails g bullet:install

The generate command will auto generate the default configuration and may ask to include in the test environment as well. See below for custom configuration.

Note: make sure bullet gem is added after activerecord (rails) and mongoid.

Configuration

Bullet won't enable any notification systems unless you tell it to explicitly. Append to config/environments/development.rb initializer with the following code:

config.after_initialize do
  Bullet.enable = true
  Bullet.sentry = true
  Bullet.alert = true
  Bullet.bullet_logger = true
  Bullet.console = true
  Bullet.xmpp = { :account  => '[email protected]',
                  :password => 'bullets_password_for_jabber',
                  :receiver => '[email protected]',
                  :show_online_status => true }
  Bullet.rails_logger = true
  Bullet.honeybadger = true
  Bullet.bugsnag = true
  Bullet.appsignal = true
  Bullet.airbrake = true
  Bullet.rollbar = true
  Bullet.add_footer = true
  Bullet.skip_html_injection = false
  Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
  Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware', ['my_file.rb', 'my_method'], ['my_file.rb', 16..20] ]
  Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' }
end

The notifier of Bullet is a wrap of uniform_notifier

The code above will enable all of the Bullet notification systems:

  • Bullet.enable: enable Bullet gem, otherwise do nothing
  • Bullet.alert: pop up a JavaScript alert in the browser
  • Bullet.bullet_logger: log to the Bullet log file (Rails.root/log/bullet.log)
  • Bullet.console: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
  • 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.
  • Bullet.rails_logger: add warnings directly to the Rails log
  • Bullet.honeybadger: add notifications to Honeybadger
  • Bullet.bugsnag: add notifications to bugsnag
  • Bullet.airbrake: add notifications to airbrake
  • Bullet.appsignal: add notifications to AppSignal
  • Bullet.rollbar: add notifications to rollbar
  • Bullet.sentry: add notifications to sentry
  • Bullet.add_footer: adds the details in the bottom left corner of the page. Double click the footer or use close button to hide footer.
  • Bullet.skip_html_injection: prevents Bullet from injecting code into the returned HTML. This must be false for receiving alerts, showing the footer or console logging.
  • Bullet.skip_http_headers: don't add headers to API requests, and remove the javascript that relies on them. Note that this prevents bullet from logging warnings to the browser console or updating the footer.
  • Bullet.stacktrace_includes: include paths with any of these substrings in the stack trace, even if they are not in your main app
  • Bullet.stacktrace_excludes: ignore paths with any of these substrings in the stack trace, even if they are not in your main app. Each item can be a string (match substring), a regex, or an array where the first item is a path to match, and the second item is a line number, a Range of line numbers, or a (bare) method name, to exclude only particular lines in a file.
  • Bullet.slack: add notifications to slack
  • Bullet.raise: raise errors, useful for making your specs fail unless they have optimized queries
  • Bullet.always_append_html_body: always append the html body even if no notifications are present. Note: console or add_footer must also be true. Useful for Single Page Applications where the initial page load might not have any notifications present.
  • Bullet.skip_user_in_notification: exclude the OS user (whoami) from notifications.

Bullet also allows you to disable any of its detectors.

# Each of these settings defaults to true

# Detect N+1 queries
Bullet.n_plus_one_query_enable     = false

# Detect eager-loaded associations which are not used
Bullet.unused_eager_loading_enable = false

# Detect unnecessary COUNT queries which could be avoided
# with a counter_cache
Bullet.counter_cache_enable        = false

Note: When calling Bullet.enable, all other detectors are reset to their defaults (true) and need reconfiguring.

Safe list

Sometimes Bullet may notify you of query problems you don't care to fix, or which come from outside your code. You can add them to a safe list to ignore them:

Bullet.add_safelist :type => :n_plus_one_query, :class_name => "Post", :association => :comments
Bullet.add_safelist :type => :unused_eager_loading, :class_name => "Post", :association => :comments
Bullet.add_safelist :type => :counter_cache, :class_name => "Country", :association => :cities

If you want to skip bullet in some specific controller actions, you can do like

class ApplicationController < ActionController::Base
  around_action :skip_bullet, if: -> { defined?(Bullet) }

  def skip_bullet
    previous_value = Bullet.enable?
    Bullet.enable = false
    yield
  ensure
    Bullet.enable = previous_value
  end
end

Log

The Bullet log log/bullet.log will look something like this:

  • N+1 Query:
2009-08-25 20:40:17[INFO] USE eager loading detected:
  Post => [:comments]·
  Add to your query: .includes([:comments])
2009-08-25 20:40:17[INFO] Call stack
  /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
  /Users/richard/Downloads/test/app/controllers/posts_controller.rb:7:in `index'

The first log entry is a notification that N+1 queries have been encountered. The remaining entry is a stack trace so you can find exactly where the queries were invoked in your code, and fix them.

  • Unused eager loading:
2009-08-25 20:53:56[INFO] AVOID eager loading detected
  Post => [:comments]·
  Remove from your query: .includes([:comments])
2009-08-25 20:53:56[INFO] Call stack

These lines are notifications that unused eager loadings have been encountered.

  • Need counter cache:
2009-09-11 09:46:50[INFO] Need Counter Cache
  Post => [:comments]

XMPP/Jabber and Airbrake Support

see https://github.com/flyerhzm/uniform_notifier

Growl Support

Growl support is dropped from uniform_notifier 1.16.0, if you still want it, please use uniform_notifier 1.15.0.

Important

If you find Bullet does not work for you, please disable your browser's cache.

Advanced

Work with ActiveJob

Include Bullet::ActiveJob in your ApplicationJob.

class ApplicationJob < ActiveJob::Base
  include Bullet::ActiveJob if Rails.env.development?
end

Work with other background job solution

Use the Bullet.profile method.

class ApplicationJob < ActiveJob::Base
  around_perform do |_job, block|
    Bullet.profile do
      block.call
    end
  end
end

Work with sinatra

Configure and use Bullet::Rack.

configure :development do
  Bullet.enable = true
  Bullet.bullet_logger = true
  use Bullet::Rack
end

If your application generates a Content-Security-Policy via a separate middleware, ensure that Bullet::Rack is loaded before that middleware.

Run in tests

First you need to enable Bullet in test environment.

# config/environments/test.rb
config.after_initialize do
  Bullet.enable = true
  Bullet.bullet_logger = true
  Bullet.raise = true # raise an error if n+1 query occurs
end

Then wrap each test in Bullet api.

# spec/rails_helper.rb
if Bullet.enable?
  config.before(:each) do
    Bullet.start_request
  end

  config.after(:each) do
    Bullet.perform_out_of_channel_notifications if Bullet.notification?
    Bullet.end_request
  end
end

Debug Mode

Bullet outputs some details info, to enable debug mode, set BULLET_DEBUG=true env.

Contributors

https://github.com/flyerhzm/bullet/contributors

Demo

Bullet is designed to function as you browse through your application in development. To see it in action, you can follow these steps to create, detect, and fix example query problems.

1. Create an example application

$ rails new test_bullet
$ cd test_bullet
$ rails g scaffold post name:string
$ rails g scaffold comment name:string post_id:integer
$ bundle exec rails db:migrate

2. Change app/models/post.rb and app/models/comment.rb

class Post < ApplicationRecord
  has_many :comments
end

class Comment < ApplicationRecord
  belongs_to :post
end

3. Go to rails c and execute

post1 = Post.create(:name => 'first')
post2 = Post.create(:name => 'second')
post1.comments.create(:name => 'first')
post1.comments.create(:name => 'second')
post2.comments.create(:name => 'third')
post2.comments.create(:name => 'fourth')

4. Change the app/views/posts/index.html.erb to produce a N+1 query

<% @posts.each do |post| %>
  <tr>
    <td><%= post.name %></td>
    <td><%= post.comments.map(&:name) %></td>
    <td><%= link_to 'Show', post %></td>
    <td><%= link_to 'Edit', edit_post_path(post) %></td>
    <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>

5. Add the bullet gem to the Gemfile

gem "bullet"

And run

bundle install

6. enable the Bullet gem with generate command

bundle exec rails g bullet:install

7. Start the server

$ rails s

8. Visit http://localhost:3000/posts in browser, and you will see a popup alert box that says

The request has unused preload associations as follows:
None
The request has N+1 queries as follows:
model: Post => associations: [comment]

which means there is a N+1 query from the Post object to its Comment association.

In the meantime, there's a log appended into log/bullet.log file

2010-03-07 14:12:18[INFO] N+1 Query in /posts
  Post => [:comments]
  Add to your finder: :include => [:comments]
2010-03-07 14:12:18[INFO] N+1 Query method call stack
  /home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:14:in `_render_template__600522146_80203160_0'
  /home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:11:in `each'
  /home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:11:in `_render_template__600522146_80203160_0'
  /home/flyerhzm/Downloads/test_bullet/app/controllers/posts_controller.rb:7:in `index'

The generated SQL is:

Post Load (1.0ms)   SELECT * FROM "posts"
Comment Load (0.4ms)   SELECT * FROM "comments" WHERE ("comments".post_id = 1)
Comment Load (0.3ms)   SELECT * FROM "comments" WHERE ("comments".post_id = 2)

9. To fix the N+1 query, change app/controllers/posts_controller.rb file

def index
  @posts = Post.includes(:comments)

  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @posts }
  end
end

10. Refresh http://localhost:3000/posts. Now there's no alert box and nothing new in the log.

The generated SQL is:

Post Load (0.5ms)   SELECT * FROM "posts"
Comment Load (0.5ms)   SELECT "comments".* FROM "comments" WHERE ("comments".post_id IN (1,2))

N+1 query fixed. Cool!

11. Now simulate unused eager loading. Change app/controllers/posts_controller.rb and app/views/posts/index.html.erb

def index
  @posts = Post.includes(:comments)

  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @posts }
  end
end
<% @posts.each do |post| %>
  <tr>
    <td><%= post.name %></td>
    <td><%= link_to 'Show', post %></td>
    <td><%= link_to 'Edit', edit_post_path(post) %></td>
    <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>

12. Refresh http://localhost:3000/posts, and you will see a popup alert box that says

The request has unused preload associations as follows:
model: Post => associations: [comment]
The request has N+1 queries as follows:
None

Meanwhile, there's a line appended to log/bullet.log

2009-08-25 21:13:22[INFO] Unused preload associations: PATH_INFO: /posts;    model: Post => associations: [comments]·
Remove from your finder: :include => [:comments]

13. Simulate counter_cache. Change app/controllers/posts_controller.rb and app/views/posts/index.html.erb

def index
  @posts = Post.all

  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @posts }
  end
end
<% @posts.each do |post| %>
  <tr>
    <td><%= post.name %></td>
    <td><%= post.comments.size %></td>
    <td><%= link_to 'Show', post %></td>
    <td><%= link_to 'Edit', edit_post_path(post) %></td>
    <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>

14. Refresh http://localhost:3000/posts, then you will see a popup alert box that says

Need counter cache
  Post => [:comments]

Meanwhile, there's a line appended to log/bullet.log

2009-09-11 10:07:10[INFO] Need Counter Cache
  Post => [:comments]

Copyright (c) 2009 - 2022 Richard Huang ([email protected]), released under the MIT license

bullet's People

Contributors

2collegebums avatar adamzapasnik avatar aercolino avatar ahorner avatar amatsuda avatar ccutrer avatar danp60 avatar dtaniwaki avatar flyerhzm avatar gabrieltaylor avatar gvalmon avatar iainbeeston avatar kehra avatar lowjoel avatar madrobby avatar nathanl avatar nicolas-fricke avatar olleolleolle avatar philostler avatar quintinm-dev avatar rainux avatar randikabanura avatar riffraff avatar rmehner avatar takatoshiono avatar tricknotes avatar viraptor avatar westonganger avatar ydah avatar yhirano55 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bullet's Issues

Inconsistent suggestions with nested association calls

Using Rails 2.3.5 with Bullet 2.1.0, I have a model like this

MainModel < ActiveRecord::Base
  belongs_to :sub_model

  named_scope :my_finder, lambda {
     {:include => :sub_model, :conditions => ["...."] }
  }
end

SubModel < ActiveRecord::Base
   belongs_to :some_data
end

SomeData < ActiveRecord::Base
end

And my list is something like

results = MainModel.my_finder
results.each do |result|
  result.sub_model.some_data
end

Bullet now says

 N+1 Query detected
    SubModel => [:some_data]
    Add to your finder: :include => [:some_data]

First and second line are correct. But in the third line, Bullet should suggest :include => {:sub_model => :some_data}

If I add the ladder one, the N+1 Queries are gone. But Bullet complains

Unused Eager Loading detected
  SubModel => [:some_data]
  Remove from your finder: :include => [:some_data]

modifying hash while iterating may cause failure (1.9.2) or 100% cpu (1.8.7)

I'm sorry but I am currently unable to reproduce this in a test case: basically changing an enumerable while iterating is undefined behaviour in ruby <1.9 but is explicitly forbidden in 1.9, which revelaed the problem in Bullet::Detector::Association#add_eager_loadings: the eager_loadings structure is looped while at the same time objects are removed and added to it which at least in one situation reliably caused CPU spikes for me on 1.8.7, (and the error on 1.9) but the result may vary depending on os, compiler, cpu etc. so it's very hard to reproduce.

I am not sure why this code is structured thus, so I am unable to provide an insight in this, but I have a fix in 7b6cd07 which seems to still let tests pass. Probably some tests for this are waiting to be written :)

Freezing script/server

Hi, I'm trying to make bullet work, but unfortunately it completely freezes the app. Nothing is logged on the console, I only see a query in development.log (the first one) and after nothing else. If I remove bullet everything returns to normality.
I'm using rails 2.3.5 on ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10]. I've tried with rack 1.0.1 and rack 1.1.0. I disabled the browser cache and tried both firefox and safari.
It just loads forever - not even a timeout. Growl seems to start correctly.
What am I doing wrong ?

undefined method alert=

Hi,

I'm running Rails 2.3.3, and I just upgraded the bullet gem from 1.4.1 to 1.5.4, and I get the following when I start the app:

/config/environments/development.rb:27:in load_environment': undefined methodalert=' for Bullet::Association:Class (NoMethodError)

Reverting to version 1.4.1 (the previous I had) fixes this.

Thoughts?

Thanks,
Mike

Add ability to detect poorly used include? calls

Thanks for a great tool!

Another common issue with sometimes disastrous consequences similar to those of N+1 queries is improper .include? calls.

I.E.

class MyObject
has_many :mappings
has_many :other_objects, :through => :mappings
end

my_object.other_objects.include?(my_other_object)

would be better implemented as

my_object.other_objects.where(:id => my_other_object.id).exists?

@mtodd PDI

Issues with Rake?

This might be an issue on my local box, but after installing bullet I get this error anytime I run rake:

rake aborted!
uninitialized constant Rails::Initializer::Bullet
$PATH/Rakefile:10

I have the config files in my development.rb file copy/pasted directly from the readme. Though Bullet works fine and the Rails app works fine. I only get that error when running Rake. Any ideas?

Problem with bundler08 and bullet 2.0 pre releases

ERROR:  While executing gem ... (ArgumentError)
    Illformed requirement ["v2.0.0.beta.2"]

My Gemfile had following line:
gem "bullet", ">= 2.0.0"

(I know this is more bundler problem, but could you change naming scheme for versions?)

typo in Rails 2.2 support code

WIth Bullet installed in Rails 2.2 application it failed on every request complaining about missing perform_bullet_out_of_channel_notifications method call from action_controller2.rb.

After changing to perform_out_of_channel_notifications it started working.

Reproduced with 2.0.1 gem

Problem with Bullet and named scopes?

So I'm just trying out Bullet for the first time, and one of the warnings I get is this:

Unused Eager Loading in /blog
User => [:roles, "roles"]
Remove from your finder: :include => [:roles, :roles]

OK, so I do a search for User., which returns a few results, but none of them is including roles. So then I do a search for :include => 'roles (and various other ways of displaying it). The only result I get is for a named scope I have:

named_scope :bloggers, :include => 'roles', :joins => :posts, :conditions => ["roles.name IN ('Admin', 'Editor','Blogger') AND users.name <> 'Administrator'"]

It's ugly, but roles is definitely being used here. So I'm unsure why Bullet is telling me to remove it? I tried a number of other parts of my site, and it seems in every area, almost all of the warnings Bullet throws are actually for named scopes. Am I misunderstanding something?

Installed, configured but no output

I've installed bullet 1.7.6 into a rails 2.3.8 app using bundler, and have added the following configuration to config/development.rb and confirmed growl is working ("Bullet Growl notifications have been turned on" appears on first request). However there is no other indication that bullet is working - nothing in log/bullet.log and no growl or javascript messages. I'm pretty sure I'm hitting pages which should detect problems. This is on Mac OS 10.6.4 using passenger (also tried script/server).

config.after_initialize do
Bullet.enable = true
Bullet.alert = true
Bullet.bullet_logger = true
Bullet.console = true
Bullet.growl = true
Bullet.rails_logger = true
Bullet.disable_browser_cache = true
end

Deep eager loading not properly detected?

I'm running into an issue with deep eager loading. If I do this:

:include => [:hotel, :extras]

bullet tells me that I need to eager load locations for Hotel (it says I need ":include => [:location]" for Hotel). If I then do:

:include => [{:hotel => :location}, :extras]

then bullet tells me that I have an unused eager load (for the above, although it doesn't show the deep eager load part for the hotel, just says, ":include => [:extras, :hotel]").

I'm wondering if deep eager loading is not handled well in Bullet or if I'm doing something wrong, or? I did see the one other issue saying that eager loading was not put into the log, but I'm unclear if that's related or different for default_scopes, etc.

Possible to turn bullet off for part of an action?

Is it possible to turn bullet off for part of an action I don't want any bullet logs for? The part in question is a rather complicated sql structure (sti combined with polymorphism structured in a tree with ancestry) and no matter what suggestion of bullet I follow, it either wants me to remove one include and add another, and when I do that it suggests vice-versa. I logged the SQL commands and found the better :include option of both variants and now I want to do something like:

silence_bullet do
  my_complicated_finder :include => :xyz
end

Breaking on deep eager loading

If I have this in my model:
default_scope :include=>{:foo=>:bar}

But I don't use the Bar model in the view, then I get an error:
undefined method `to_sym' for {:foo=>:bar}:Hash

on /plugins/bullet/lib/bullet/association.rb:84:in `log_bad_associations'

undefined method `add' for nil:NilClass

I got this during a migration. I worked around it by removing bullet from my configuration file during the migration.

undefined method `add' for nil:NilClass
vendor/rails/activesupport/lib/active_support/whiny_nil.rb:52:in `method_missing'
/Library/Ruby/Gems/1.8/gems/bullet-2.0.0.beta.3/lib/bullet/detector/n_plus_one_query.rb:21:in `create_notification'
/Library/Ruby/Gems/1.8/gems/bullet-2.0.0.beta.3/lib/bullet/detector/n_plus_one_query.rb:14:in `call_association'
/Library/Ruby/Gems/1.8/gems/bullet-2.0.0.beta.3/lib/bullet/active_record2.rb:84:in `load_target'
vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:212:in `method_missing'

I am on version '2.0.0.beta.3'

Bullet stops script/server from executing

I'm getting this after everything was installed:

=> Booting Mongrel
=> Rails 2.3.4 application starting on http://0.0.0.0:3000
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:585:in `to_constant_name': Anonymous modules have no name to be referenced by (ArgumentError)
    from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:391:in `qualified_name_for'
    from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:104:in `const_missing'
    from /Library/Ruby/Gems/1.8/gems/flyerhzm-bullet-1.4.0/lib/bullet.rb:9:in `enable='
    from /Users/kieran/Work/wfcc_rosters/config/environments/development.rb:26:in `load_environment'

I've set it up exactly as the README describes. Line 26 of config/environments/development.rb is

Bullet.enable = true

can't modify frozen string in /lib/bulletware.rb:15:in `<<'

This happens in my app when I have some caching going on and I'm rendering out the response body in an around or before filter.

This issue is caused by the fact that response.body is frozen at this point and cant be modified in the bullet middleware call method (to place in the javascript). The solution (for me) was to replace line 15 in bulletware.rb with the following;

    response_body = (response.body.frozen? ? response.body : (response.body << Bullet.javascript_notification))

(i.e. check if frozen before modifying body) -- Obviously doing this means I only get the Growl notification message and NO javascript message. But its enough for me to see whats going on.

Invalid gemspec for uniform_notifier-1.0.2.gemspec

When i try and bundle install bullet within my app i am unable to relaunch my server. Im getting the following turning up in my log file:

Invalid gemspec in [/Users/peterroome/.rvm/gems/ruby-1.9.2-p136/specifications/uniform_notifier-1.0.2.gemspec]: Illformed requirement ["#<Syck::DefaultKey:0x00000100d16ce8> 3.0"]

My Gemfile looks like this:
source :rubygems

gem 'rails', '3.1.1'
gem "authlogic"
gem 'nokogiri'
gem 'rockstar'

gem 'delayed_job', '2.1.2'
gem 'hirefireapp'

gem 'ruby-mp3info', :require => 'mp3info'
gem 'xml-simple'
gem 'httparty'
gem 'paperclip'
gem "aws-sdk"
gem 'thin'
gem 'unicorn'
gem 'pg'
gem 'redis', '2.2.2'
gem 'kaminari'
gem 'sendgrid'

gem 'asset_sync'

group :assets do
gem 'sass-rails', " ~> 3.1.0"
gem 'coffee-rails', " ~> 3.1.0"
gem 'uglifier'
end

gem 'jquery-rails'
gem 'exceptional'

gem 'yajl-ruby'
gem 'ruby-prof'

gem "bullet", :group => "development"

I've tried installing bullet via bundler and via gem install and i've also tried installing uniform_notifier via both of these methods too. None of which seems to help.

When i do bundle show bullet i get:

Invalid gemspec in [/Users/peterroome/.rvm/gems/ruby-1.9.2-p136/specifications/uniform_notifier-1.0.2.gemspec]: Illformed requirement ["#<Syck::DefaultKey:0x00000100c8f3b0> 3.0"] Invalid gemspec in [/Users/peterroome/.rvm/gems/ruby-1.9.2-p136/specifications/uniform_notifier-1.0.2.gemspec]: Illformed requirement ["#<Syck::DefaultKey:0x00000100c8f3b0> 3.0"] Could not find uniform_notifier-1.0.2 in any of the sources

So i suspect the problem is likely with uniform_notifier but as i said, trying to install this gem prior to bullet hasn't helped.

Have you got any suggestions please?

EDIT: I've just added bullet to a new Rails 3.2 gemfile and run bundle install and i'm having the same problem there too.

Bullet makes Association Nulls Whiny

I've got a simple model/association set up:

class Computer < ActiveRecord::Base
  belongs_to :lifecycle_status 
end

class LifecycleStatus < ActiveRecord::Base                                                                                                                                                 
  has_many :computers, :dependent => :nullify
end

In my Computer's view I have the following:

<%= @computer.lifecycle_status %>

With Bullet disabled, it works fine, just printing out an empty string.

With Bullet enabled I get the following:

undefined method `id' for nil:NilClass

Even attempting to check if @computer.lifecycle_status.nil? causes the error, so I can't avoid it.

Am I doing something wrong or is there a way to prevent Bullet from trying to resolve null associations?

Cooperating with devise

Using Bullet 2.0.0 beta 2, Rails 3 beta 3 and Devise 1.1rc1, bullet causes an exception:
undefined method `body' for #Array:0xb27580c
in lib/bulletware.rb:30.

Seems that the relevant response is an array but not empty, so ruby stumbles over
(response.is_a?(Array) && response.empty?) || !response.body.is_a?(String) || response.body.empty?

STI and acts_as_tree

Looks like an edge case, for your information.

Models:

class Document < AR
acts_as_tree
belongs_to :author
end

class Page < Document
end

class Folder < Document
end

In the controller:

@document = Document.find_by_permalink(params[:id], :include => [:author])

Error:

Unused Eager Loading detected
Folder => [:author]
Remove from your finder: :include => [:author]
N+1 Query detected
Page => [:author]
Add to your finder: :include => [:author]

I hope this helps someone!

Bullet fails when response body is Rack::File

I have a Rails 3 app where I am adding ActionDispatch::Static middlware to server some additional static content. This middleware is actually added by a separate Rails engine, after the Bullet middleware is added to the stack (I can print out the stack after my engine adds its ActionDispatch::Static).

When GETing static files from this instance of ActionDispatch::Static, I get the error:

undefined method `body' for #<Rack::File:0x1049060f0>
/gems/bullet-2.3.1/lib/bullet/rack.rb:31:in `empty?'
/gems/bullet-2.3.1/lib/bullet/rack.rb:12:in `call'

It seems that since Rack::File is not an Array (but does respond to #each as the Rack spec mandates), Bullet assumes it responds to the #body method.

Why bullet so slow

Something it stopped my server.

I suppose I can use it when I running test, it is horrible. Before I use bullet all test take 15 mins, after enable bullet it takes 10 hours.

Line numbers?

Is there anyway Bullet could output the line number of the finder that needs to be modified? I've taken over a convoluted app, and am actually having trouble finding the finders Bullet is telling me to modify.

README documenation is incorrect for Growl support

Within the Growl section of your documentation, you state the following:

Bullet.growl_password = { :password => 'growl password' }

...but should be the following:

Bullet.growl = { :password => 'growl password' }

Bullet drastically slows down nested eager associations

I'm using Rails 3.0.0.beta3 and have a nested eager load that drives my CPU to 100% and takes 30-60 seconds to complete. App looks something like this:

Models:

Post (has_many :comments)

Comment (belongs_to :post, has_many :ratings)

Rating (belongs_to :comment)

Sample queries:

Takes < 0.01 sec : r = Rating.limit(20).includes(:comment)

Takes < 0.01 sec : c = Comment.limit(20).includes(:post)

Takes > 30 sec : r = Rating.limit(20).includes(:comment => :post)

The last query, with the nested eager load, drives my CPU to 100% for a very long time. The database queries (seen in development.log) all only take a few milliseconds. The long delay is between the second and third queries (i.e. between the "select comments" and "select posts").

After disabling Bullet, the nested eager load takes just a few milliseconds.

I've built a barebones Rails 3.0.0beta3 app with a sample DB that demonstrates this, in case you need it.

Thanks for the great gem!

Incorrect unused eager loading warning

Bullet seems to be a bit overzealous about unused eager loading warnings. When i load through an association like this:

Category.find_by_name(params[:category_name], :include => {:submissions => :user}, :order => "id DESC")

Bullet seems to think that I don't need the submissions collection even though it is used in the view and also used to render a partial.

Rails 3.1.1 fail on start with bullet master

This is the error:

.rvm/gems/ruby-1.9.2-p290@execuzone/bundler/gems/bullet-662e26635410/lib/bullet/active_record3.rb:23:in `enable': uninitialized constant ActiveRecord::AssociationPreload (NameError)

Require flag on script/server for bullet to load (a la ruby-debug)

Thanks for the awesome gem.

It would be nice to selectively activate Bullet when you start a server with a flag. The other contributor on my projects is a designer and he gets annoyed with all the Growl notifications and having to disable his browser cache to avoid the nil.include? error. It would be nice to have an option such as script/server --bullet that allows me to enable Bullet when I want to use it.

View html contents spilling out into rails logs

With Bullet enabled, even if all alerts are off, view html contents are spilling into rails logs. This makes it hard to wade through the log to find Bullet messages for exact line number messages. Probably just an errant puts statement somewhere.

config.after_initialize do
Bullet.enable = true
Bullet.alert = false
Bullet.bullet_logger = false
Bullet.console = false
Bullet.growl = false
Bullet.rails_logger = false
Bullet.disable_browser_cache = false
end

nil.collect error

Hi there,

i get a The error occurred while evaluating nil.collect
bullet (2.0.1) lib/bullet/detector/unused_eager_association.rb:26:in `call_object_association'

error on ree-1.8.7

i solved the problem with changing flatten! in flatten in line 12 in association.rb

flatten! gives back nil when there are no changes.

Under 1.9.2 Bullet creates millions of extra strings

In my Rails 2.3.11 site we were trying to move to ruby 1.9.2p136 from REE and (much to our surprise) everything was much slower. After some debugging I found that just calling a Rails dynamic finder (Model.find_by_some_column) in a loop created 20 million more strings than it did in REE. After removing Bullet I could run my test script in 1/6 the time because I spent less time in garbage collection.

chokes on polymorphic + includes

Has anyone else had this issue?

I have 2 models:

Place and an Address where address is polymorphic. Where I try to run a query like:

Place.includes(:address).joins(:address).where(:addresses =>{:city => "someCity"})

I get the following error thrown:

RuntimeError: can't add a new key into hash during iteration

from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/bullet-2.0.1/lib/bullet/registry/association.rb:5:in merge!' from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/bullet-2.0.1/lib/bullet/registry/association.rb:5:inmerge'
from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/bullet-2.0.1/lib/bullet/detector/association.rb:52:in block in add_eager_loadings' from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/bullet-2.0.1/lib/bullet/registry/base.rb:15:ineach'
from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/bullet-2.0.1/lib/bullet/registry/base.rb:15:in each' from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/bullet-2.0.1/lib/bullet/detector/association.rb:42:inadd_eager_loadings'
from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/bullet-2.0.1/lib/bullet/active_record3.rb:32:in preload_associations' from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/activerecord-3.0.6/lib/active_record/relation.rb:68:inblock in to_a'
from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/activerecord-3.0.6/lib/active_record/relation.rb:68:in each' from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/activerecord-3.0.6/lib/active_record/relation.rb:68:into_a'
from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/bullet-2.0.1/lib/bullet/active_record3.rb:10:in to_a' from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/activerecord-3.0.6/lib/active_record/relation.rb:359:ininspect'
from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/railties-3.0.6/lib/rails/commands/console.rb:44:in start' from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/railties-3.0.6/lib/rails/commands/console.rb:8:instart'
from /home/joelmats/.rvm/gems/ruby-1.9.2-p136/gems/railties-3.0.6/lib/rails/commands.rb:23:in `<top (required)>'

growl_password

Setting the growl_password no longer seems to be possible - I unpacked the gem and had a brief look around, found nothing. Is this no longer supported?

A suggestion (not really an issue :))

I'd like to see bullet run when i run my functional/integration tests, just instead of popping growl notification have it save notifications to a log on @config/bullet.log@ or something.

Bullet.notification? can crash rack..

We have a chain of scopes on a model on which bullet chokes when evaluating check_unused_preload_associations. When this exception (due to calling flatten!) reaches the rack layer, we get an error page. This has led us to do the following patch, so that we do not have to disable bullet altogether. It could be complicated to isolate the lower-level crash, but at the rack level, we think allowing the exception to bubble up is bad form (logging would be better).

module Bullet
  def self.notification?
    Bullet::Detector::UnusedEagerAssociation.check_unused_preload_associations
    notification_collector.notifications_present?
  rescue 
    false
  end
end

Seems to be failing in rails 3.2.1

Seems to be failing in rails 3.2.1

config.after_initialize do
  Bullet.enable = true
end

gives me:

/home/rio/.gem/ruby/1.9.2/gems/bullet-2.1.0/lib/bullet/active_record2.rb:8:in 'alias_method': undefined method 'find_every' for class 'Class' (NameError)
from /home/rio/.gem/ruby/1.9.2/gems/bullet-2.1.0/lib/bullet/active_record2.rb:8:in 'singletonclass'
from /home/rio/.gem/ruby/1.9.2/gems/bullet-2.1.0/lib/bullet/active_record2.rb:7:in 'block in enable'
from /home/rio/.gem/ruby/1.9.2/gems/bullet-2.1.0/lib/bullet/active_record2.rb:6:in 'class_eval'
from /home/rio/.gem/ruby/1.9.2/gems/bullet-2.1.0/lib/bullet/active_record2.rb:6:in 'enable'
from /home/rio/.gem/ruby/1.9.2/gems/bullet-2.1.0/lib/bullet.rb:41:in 'enable='
from /myrailsapp/config/environments/development.rb:38:in 'block (2 levels) in <top (required)>'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/lazy_load_hooks.rb:34:in 'call'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/lazy_load_hooks.rb:34:in 'execute_hook'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/lazy_load_hooks.rb:43:in 'block in run_load_hooks'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/lazy_load_hooks.rb:42:in 'each'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/lazy_load_hooks.rb:42:in 'run_load_hooks'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/application/finisher.rb:59:in 'block in <module:Finisher>'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/initializable.rb:30:in 'instance_exec'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/initializable.rb:30:in 'run'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/initializable.rb:55:in 'block in run_initializers'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/initializable.rb:54:in 'each'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/initializable.rb:54:in 'run_initializers'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/application.rb:136:in 'initialize!'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/railtie/configurable.rb:30:in 'method_missing'
from /myrailsapp/config/environment.rb:5:in '<top (required)>'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:251:in 'require'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:251:in 'block in require'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:236:in 'load_dependency'
from /home/rio/.gem/ruby/1.9.2/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:251:in 'require'
from /myrailsapp/config.ru:4:in 'block in <main>'
from /home/rio/.gem/ruby/1.9.2/gems/rack-1.4.1/lib/rack/builder.rb:51:in 'instance_eval'
from /home/rio/.gem/ruby/1.9.2/gems/rack-1.4.1/lib/rack/builder.rb:51:in 'initialize'
from /myrailsapp/config.ru:1:in 'new'
from /myrailsapp/config.ru:1:in '<main>'
from /home/rio/.gem/ruby/1.9.2/gems/rack-1.4.1/lib/rack/builder.rb:40:in 'eval'
from /home/rio/.gem/ruby/1.9.2/gems/rack-1.4.1/lib/rack/builder.rb:40:in 'parse_file'
from /home/rio/.gem/ruby/1.9.2/gems/rack-1.4.1/lib/rack/server.rb:200:in 'app'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/commands/server.rb:46:in 'app'
from /home/rio/.gem/ruby/1.9.2/gems/rack-1.4.1/lib/rack/server.rb:301:in 'wrapped_app'
from /home/rio/.gem/ruby/1.9.2/gems/rack-1.4.1/lib/rack/server.rb:252:in 'start'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/commands/server.rb:70:in 'start'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/commands.rb:55:in 'block in <top (required)>'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/commands.rb:50:in 'tap'
from /home/rio/.gem/ruby/1.9.2/gems/railties-3.2.1/lib/rails/commands.rb:50:in '<top (required)>'
from script/rails:6:in 'require'

not compatible with rails 3.1rc4

Hello, tried to use bullet on a rails 3.1rc4 application with the following settings in config/environments/development.rb :
config.after_initialize do
Bullet.enable = true
Bullet.alert = true
Bullet.bullet_logger = true
Bullet.console = true
Bullet.growl = false
Bullet.rails_logger = true
Bullet.disable_browser_cache = true
end

And then the application wouldn't start because of this error :
.rvm/gems/ruby-1.9.2-p180@rails_3_1rc4/gems/bullet-2.0.1/lib/bullet/active_record2.rb:7:in alias_method': undefined methodfind_every' for class `Class' (NameError)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.