Reputation: 2748
This might be a trivial point, but I don't understand it and it bothers me. Going through the Ruby on Rails Tutorial by Michael Hartl, there is this method definition :
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to user
else
flash.now[:danger] = "Invalid email/password combination"
render 'new'
end
end
What I don't understand is why the conjunction
user && user.authenticate(params[:session][:password])
is neccessary. Surely, there is no case in which user.authenticate will return "true" if the user object is empty, and hence, nil. Is this just a matter of style, or does 'user &&' do something subtle in this expression?
Upvotes: 0
Views: 136
Reputation: 369623
Why don't you just ask Ruby herself about the difference?
user = nil
if user && user.authenticate(nil) then end
if user user.authenticate(nil) then end
# NoMethodError: undefined method `authenticate' for nil:NilClass
As you can see, nil
doesn't have an authenticate
method (why would it), so trying to call authenticate
on nil
will raise
a NoMethodError
.
Boolean operators are evaluated lazily from left to right (sometimes known as "short-circuiting") only as far as is needed to determine the result. Since user
is nil
, it is already known that the result of the entire conditional must be falsy, no matter what the right operand is, and so the right operand is never evaluated, and therefore, the non-existing method is never called.
Note: I'm not trying to be glib here, I'm trying to show you a powerful learning tool: if you are wondering "what happens if I do XYZ", just do XYZ and see what happens! Contrary, to, say, chemistry, experimenting is completely safe in programming. (Well … you could delete your harddrive, if you're really stupid, but if you do your experiments in a sandboxed environment, you'll be fine. Accidentally deleting valuable data is highly unlikely unless you are toying around with the File
or FileUtils
classes.)
Upvotes: 1
Reputation: 369
if user
would be the same as if user.present?
. So if its nil, it goes to the else statement, if its true, then it runs the second statement being user.authenticate(params[:session][:password])
Upvotes: 2
Reputation: 786
Trying to do this part: user.authenticate(params[:session][:password])
without first knowing if the object exists will throw an error. So you need to make sure you have the user
object before you try to run .authenticate
on it. Does that make sense?
Upvotes: 1