Posted by: tszao | June 11, 2008

rails 2 find_by and find differences

So this has been a day of bug tracking.

I use a very simple authentication process for a site that I am writing in Rails 2.0. Here is the def in my model.

#Original def
def self.authenticate(user_info)
user = find_by_username(user_info[:username])
if user.username == user_info[:username] && user.hashed_password == hashed(user_info[:password])
return user
end
end

This may look familiar to some out there if you read the same materials that I read for pre-Rails 2 literature. While trying to get all of my login stuff working with Rails 2 this creates a …

You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.username

This was a royal pain in the butt to fix but here is a work-around. I am not sure how viable it is as a solution, but I do know that it fixed my problem and now I can move on to the rest of the site without this thing hanging over my head.

Apparently in Rails 2.0 the way functions are called work differently than in Rails 1. I needed to use a different query to accomplish the same task. However, this particular query returns an array. So after you check the length of the recordset ( no [0] ) then you have to use the array ( with [0] ) to work with the results. Crazy thing is that when the results are returned to the controller, the need for the array disappears.

#work around def
def self.authenticate(user_info)
#get user using find instead of find_by_username
user = User.find(:all, :conditions => ["username = ?", user_info[:username]] )
#to check length of object you don’t need [0]
if user.length > 0
#to use the object you do need the [0]
if user[0].username == user_info[:username] && user[0].hashed_password == hashed(user_info[:password])
#when the result gets back to the controller the [0] will not need to be used
return user[0]
end
end
end

Let me know if you have a better solution for the work around.


Responses

  1. You have a nil object when you didn’t expect it!
    The error occurred while evaluating nil.username

    simply replace
    if user.username == user_info[:username] && user.hashed_password == hashed(user_info[:password])

    with
    if user && user.username == user_info[:username] && user.hashed_password == hashed(user_info[:password])

  2. Couldn’t you also just do this?

    def self.authenticate(user_info)
    find(:first, :conditions=>{:username=>user_info[:username],:hashed_password=>hashed(user_info[:password])})
    end

  3. I’m not sure but I would be happy to give it a try. Thanks for the tip.

  4. I’m not sure but I would be happy to give it a try. Thanks for the tip.


Leave a response

Your response:

Categories