flyerhzm / bullet

help to kill N+1 queries and unused eager loading
MIT License
7.07k stars 432 forks source link

Calling .id on nil error #68

Closed emeryamiller closed 12 years ago

emeryamiller commented 12 years ago

After installing bullet into my app I get the following error: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id

As I've debugged this issue, I've managed to narrow down 4 cases that create the same error, but I'm not clear what might be the cause.

The first piece of code that causes this is the last line of the following method:

def people_involved
   tasks = tasks.includes(:author, :assignee).all                                                                                                                                                                                                                                                                                                                      
   tasks.each_with_object(contributors.to_a.uniq) {|task, people| people << task.author << task.assignee }.uniq.compact 
end

By replacing these lines with a safe return value (the contributors attribute of the tasks), I was able to find the next errors. They give exactly the same called id on nil error as above.

The remaining errors occurn In my RABL code (RABL is a templating language like jbuilder - https://github.com/nesquena/rabl). The lines that are commented out are the minimum lines of code that I needed to comment out in order to load my page without the errors:

glue :author do
 attribute :id => :author
end
#glue :assignee do
# attribute :id => :assignee
#end
node :project_id do |task|
#  task.project && task.project.id
end
...

The object being rendered is the task object in the code above. Oddly, the assignee causes the error while the author does not, yet they are both identical relationships, though I do override the assignee= method. in the case of the project node though, I don't override that, and it's a standard belongs_to relationship.

  belongs_to :project
  belongs_to :author, class_name:"User"
  belongs_to :assignee, class_name: "User"

In the code below I'm rendering a user object.

...
#child(:profile => :profile) do
#  attributes :location, :bio, :dob, :position, :industry
#end
...

The profile relationship is:

has_one  :profile, foreign_key: 'person_id'

Once these lines are commented out, bullet runs fine. I'm not sure where to look next in order to trace down these issues, any pointers would be appreciated.

flyerhzm commented 12 years ago

could you print the full stack trace?

emeryamiller commented 12 years ago

Thanks for responding. In a rather odd twist, after fixing the N+1's bullet indicated with the lines above commented out and fixing a number of other app/heroku issues we were having, this issue no longer appears. I put bullet back in, and everything works.

Sadly there's such a large diff between the old state and the current, I'm not sure what could have been the cause, but clearly the queries weren't directly to blame as all but one are still in the system. The task.project && task.project.id I removed because it was redundant.

Thanks again.

hypomodern commented 12 years ago

This is definitely still a problem; here's the relevant bit of a stack trace:

bullet (4.1.3) lib/bullet/detector/association.rb:40:in `add_impossible_object'
bullet (4.1.3) lib/bullet/mongoid24.rb:14:in `first'
mongoid (2.4.11) lib/mongoid/criteria.rb:45:in `first'

When the #first returns nil, association.rb:40 tries to call nil.id.

flyerhzm commented 12 years ago

please try HEAD code, it is supposed to be fixed.

hypomodern commented 12 years ago

Thanks, it is definitely fixed on master.

emeryamiller commented 12 years ago

Sorry. In the interest of accuracy, my last comment was inaccurate. Each of the three queries that were causing the issues above were reworked for performance reasons, and are no longer being run.