Reputation: 878
I have got a login form using the bcrypt gem. Its working as expected in the rails console. However, I get these errors on the site. Any help would be most appreciated.
NoMethodError in ManagersController#loginattempt undefined method `authenticate' for true:TrueClass
I've read a few SO posts - I used, made revisions they do not resolve the error:
For example - it is because the authenticate class doesn't have 'self' prefixed, this suggestion actually breaks the working functionality in the terminal @some_user.authenticate('***********') => true
def authenticate(password)
self.password_hash == BCrypt::Engine.hash_secret(password, password_salt)
end
or
def self.authenticate(password)
self.password_hash == BCrypt::Engine.hash_secret(password, password_salt)
end
or
def self.authenticate(password)
password_hash == BCrypt::Engine.hash_secret(password, password_salt)
end
Model
class Manager < ApplicationRecord
attr_accessor :password
validates :username, presence: true, uniqueness: true
validates :password, presence: true, on: :create
before_validation(on: :create) do
encrypt_password
end
def authenticate(password)
password_hash == BCrypt::Engine.hash_secret(password, password_salt)
end
private
def encrypt_password
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
Controller - which produces errors.
class ManagersController < ApplicationController
...
def loginattempt
@manager = Manager.where(manager_params).exists?
if @manager && @manager.authenticate(manager_params)
redirect_to managers_path, notice: 'You are logged in.'
else
redirect_to manager_login_path, notice: 'Username or Password incorrect.'
end
end
private
def manager_params
params.require(:manager).permit(:username, :password)
end
end
For posterity I believe this works now as expected - thank you to the SO community for helping me in my hour of need. Working Controller
def loginattempt
@manager = Manager.find_by_username(manager_params[:username])
if @manager.present? && @manager.authenticate(manager_params[:password])
redirect_to manager_logged_in_path(@manager), notice: 'Logged In.'
session[:logged_in] = @manager.id
else
redirect_to manager_login_path, notice: 'Username or Password incorrect.'
end
end
Upvotes: 0
Views: 37
Reputation: 724
A few things to note:
Manager.where(manager_params)
is redundant because manager_params
is something like {manager: {username: 'foo', password: 'password'}}
but where
methods takes simple hash like {username: 'foo', password: 'password'}
.find_by
instead of where
and exists?
because exists?
returns Boolean and this is not what you want. find_by
returns nil if the record doesn't exist.Manager#authenticate
method (authenticate
instance method on Manager
class) takes only password so you can use @manager.authenticate(params[:manager][:password])
instead of @manager.authenticate(manager_params)
I'd like to mention that if username
is unique we can find a user by username
only, without password.
Upvotes: 1