views:

524

answers:

5

I have a Book model in my Rails application, with various properties (aka columns in the book db table). One of these properties is "ranking".

Recently, may app has started to throw NoMethodError: undefined method 'include?' for nil:NilClass for the following code:

def some_method(book, another_arg)
  return book.ranking unless book.ranking.blank?
  ...
end

However, it's not consistent. The vast majority of the time, accessing book.ranking works -- the error is thrown maybe 2-4% of the time. If I change the code to book[:ranking] or book['ranking'] instead of book.ranking, it works 100% of the time.

Any ideas?

P.S. This problem has popped up intermittently with other models and attributes... not just Book and the ranking attribute.

+2  A: 

the book object is the one that is nil, not ranking. So having

return book.ranking unless book.nil?

should resolve the issue.

Rob Di Marco
If that's the case, shouldn't the error be `NoMethodError: undefined method `ranking' for nil:NilClass`?
NudeCanalTroll
Good point, I think I am wrong. I am looking at http://github.com/rails/rails/blob/2-3-stable/activerecord/lib/active_record/attribute_methods.rb, the method_missing (which is called when you call your ranking method) seems to call include? on @attributes . Maybe this is nil for some reason?
Rob Di Marco
I've encountered this problem: it was nothing to do with the object being nil as many on this thread have said, but it was something going wrong inside rails. "question.id" was causing a nil.include? error but "question[:id]" worked fine. I think it is something with @attributes as Rob suggests but i can't pin it down. Outputting "question.attributes" to the logger seemed to return totally normal results.
Max Williams
A: 

you should check if book is nil either

return book.ranking unless book.blank? and book.ranking.blank?
fl00r
A: 

I would use try here:

book.try(:ranking)

If book or ranking is nil then nil will be returned.

Ryan Bigg
try works, but it is not in Ruby 1.8... You have to use Active Support to get it in 1.8
severin
@severin: Given this is a Rails question I assumed that they already had Active Support used.
Ryan Bigg
A: 

You can do it also this way:

return book.ranking unless book and book.ranking

or with andand gem:

return book.ranking unless book.andand.ranking
klew
A: 

there are a few ways to protect from nil-calls:

check with if:

return book.ranking if book

use &&/and:

return book && book.ranking

use try (in Ruby 1.9 or with Rails/ActiveSupport):

return book.try(:ranking)
severin