Jason Lowry
Jason Lowry

Reputation: 3

Setting a variable equal to a function and if statements

I am very new to the Ruby language and Ruby on Rails, so I'm not entirely sure how to word my question (and will probably use incorrect terminology). The following code does not work

@user = User.find_by email: params[:session][:email] 
if @user.authenticate(params[:session][:password]) 
     # Signin @user 
else 
    # Render failed Signin 
end 

I get an error that the method authenticate is not defined for nil:Nilclass, but the following code works fine:

@user = User.find_by email: params[:session][:email] 
if @user && @user.authenticate(params[:session][:password]) 
    # Signin @user 
else 
    # Render failed Signin 
end 

I don't understand why the first code block doesn't work. When I define @user does the User.find_by method not run and set the value of @user? Or does the variables value get set only when called in the program?

EDIT: unnecessary parentheses removed.

Upvotes: 0

Views: 121

Answers (3)

Hassan Javeed
Hassan Javeed

Reputation: 464

The find_by method you used should result in a NoMethodError exception(unless you have defined that method in the User model).

You can use a dynamic finder method(http://guides.rubyonrails.org/active_record_querying.html#dynamic-finders) on any of the user's attributes like

User.find_by_email(params[:session][:email])

UPDATE: I was thinking of Rails 3 when posting the answer, Rails 4 removes dynamic finders, and the method you are using is perfectly valid.

Upvotes: 0

PericlesTheo
PericlesTheo

Reputation: 2469

Here's what I think is wrong with the first block:

In the first block, you search for a user and if not found will return nil. Then, you are trying to authenticate nil and that's why is giving you a not defined for Nil:class.

On the second block you are fixing the problem by adding the @user in your if block. Testing to see whether you actually have a retrieved user first, incase the user is not found the block will not be executed.

Upvotes: 3

dax
dax

Reputation: 11007

To start, here's a good breakdown of the && operator - what it does and doesn't do.

in your first block, in the second line:

if (@user.authenticate(params[:session][:password])) 

you don't need parentheses around @user -

if @user.authenticate(params[:session][:password]) 

You should also be using find_by_email as Hassan has pointed out.

Upvotes: 0

Related Questions