I am having trouble understanding the implementation of "Remember Me" in the Ruby on Rails Tutorial by Michael Hartl. He creates a SessionsHelper module with methods for signing in, containing the following:
module SessionsHelper
def sign_in(user)
cookies.permanent.signed[:remember_token] = [user.id, user.salt]
current_user = user
end
def current_user=(user)
@current_user = user
end
def current_user
return @current_user ||= user_from_remember_token
end
private
def user_from_remember_token
#passes array of length two as a parameter -- first slot contains ID,
#second contains SALT for encryption
User.authenticate_with_salt(*remember_token)
end
def remember_token
#ensures return of a double array in the event that
#cookies.signed[:remember_token] is nil.
cookies.signed[:remember_token] || [nil,nil]
end
end
NOTE: The authenticate_with_salt
method in the User model finds the user by the first parameter (the id) and if the user is defined and its salt is equivalent to the second parameter (the salt) then the user is returned, otherwise nil is returned.
I am having trouble understanding why we go to such lengths to test if the user has already been signed in:
In the event that the user is signed in, @current_user
is already defined by the sign_in
method and therefore the ||= in the current_user
method is meaningless.
In the event that the user is not signed in, the ||= operator in the current_user
method returns the value returned by the user_from_remember_token
method, but since cookies.signed[:remember_token] would be nil, User.authenticate_with_salt
would be passed the [nil,nil] argument and would return nil, and therefore, the current_user
method would return nil.
In short, if the current_user
method is returning @current_user if it is defined and nil otherwise, wouldn't it be much simpler to just use the conventional accessor method:
def current_user
return @current_user
end
Michael Hartl's book says that doing this would be useless because the user's sign in status would be forgotten. Why would that be the case??? Can someone please explain why we do not do this and instead use the much more intricate version posted above?