I am trying to sign in users with sessions. My controller has a method 'create' sessions:
def create
user = User.authenticate(params[:session][:email], params[:session][:password])
if user.nil?
#create an error message and re-render the signin form
flash.now[:error] = "Invalid email/password combination"
@title = "Sign in"
render 'new'
else
#sign in user and redirect to the user's show page
sign_in user
redirect_to user
end
end
the class method 'authenticate' always returns null. I uses the console to create users where 'nil?' returns false, and then I call 'authenticate' and it returns nil, everytime. I don't know why and have pored over it for hours. At first I thought it was the way I was passing the parameters to the authenticate method, but those should be right, and since the auth method doesn't even work in console with regular values it probably isnt the parameters but the structure of 'authenticate'. Here is the 'authenticate' method and its helper methods:
#defining a class method for "User" to authenticate a user who submits an email and password
def User.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
# Return true if the user's password matches the submitted password.
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user =find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
private
def encrypt_password
self.salt = make_salt if new_record?
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("{#Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
Anyone know what the deal is? and I am happy to supply anymore information. I searched around for potential solutions, and couldn't find any.
sign_in(user) method and helper methods stuff:
module SessionsHelper
def sign_in(user)
#set cookie permanently
cookies.permanent.signed[:remember_token] = [user.id, user.salt]
#define "current_user" so it can be used all over the place
self.current_user = user
end
def current_user=(user)
@current_user = user
end
def current_user
@current_user ||= user_from_remember_token
end
def signed_in?
!current_user.nil?
end
def sign_out
cookies.delete(:remember_token)
@current_user = nil
end
private
def user_from_remember_token
User.authenticate_with_salt(*remember_token)
end
def remember_token
cookies.signed[:remember_token] || [nil, nil]
end
end
users_controller:
class UsersController < ApplicationController
# GET requests are automatically handled by the "show" action.
def show
@user = User.find(params[:id])
@title = @user.name
end
def new
@user = User.new
@title = "Sign up"
end
def create
@user = User.new(params[:user])
if @user.save
sign_in @user
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
@title = "Sign up"
render 'new'
end
end
end
I see at least two problems.
1) Don't look for the :email
and :password
in the :session
. They should be in the :params
hash, not in the :session
hash inside :params
. Since you aren't getting the correct :email
, you never find the User
record, so User.authenticate
always returns nil.
2) User.authenticate
will return nil
if the email isn't found. If the email is found, it returns the value of submitted_password == encrypted_password
. You have three possible return values (nil, true, false), but only two control paths, one for nil (record not found) and one for all other cases, so you log the user in regardless of the password test result.