I have been learning Rails 3 from a video on Lynda.com , and it has been going well up until lately. What i’m trying to do currently is restrict access to certain pages unless a session is present where the user is authorized (has logged in). This is working correctly because when I try to access the pages that I want restricted, I get redirected to the login form. The problem comes up when I try to login. I put the correct username in, but when I put the password in, any password at all, it doesn’t even need to be the correct one, I get an error page I made a user admin account for development purposes, and when I login I get this error:
NameError in AccessController#attempt_login
undefined local variable or method `salt’ for #AdminUser:0x41a6a68
Application Trace:
app/models/admin_user.rb:62:in password_match?' app/models/admin_user.rb:52:in
authenticate’
app/controllers/access_controller.rb:19:in `attempt_login’
Now, I don’t know a ton about debugging as of right now, but based on the trace the method attempt_login in the access controller is the following:
def attempt_login
authorized_user = AdminUser.authenticate(params[:username], params[:password])
if authorized_user
session[:user_id] = authorized_user.id
session[:username] = authorized_user.username
flash[:notice] = "You are now logged in."
redirect_to(:action => 'menu')
else
flash[:notice] = "Invalid username/password combination."
redirect_to(:action => 'login')
end
end
I don’t know if there is an error in there that I am missing?
Anyway thanks in advance, and let me know if you need more of my code to find a solution because I am totally stuck at this point.
Elementax
Hi,
Let’s look at your error message:
Application Trace:
app/models/admin_user.rb:62:in `password_match?'
app/models/admin_user.rb:52:in `authenticate'
app/controllers/access_controller.rb:19:in `attempt_login'
You are correct that the original error is being triggered by the method attempt_login
in access_controller.rb.
However, when we inspect that, we see:
authorized_user = AdminUser.authenticate(params[:username], params[:password])
This line is calling the authenticate
method on your AdminUser
object.
The authenticate
method seems to be defined here: app/models/admin_user.rb:52
And this method is in turn calling the password_match?
method defined here: app/models/admin_user.rb:62
It is the password_match?
method that is triggering the error:
undefined local variable or method `salt' for #<AdminUser:0x41a6a68>
There could be a number of reasons for this happening.
Could you post the complete code from admin_user.rb and we’ll see if we can get to the bottom of it.
James_Hibbard:
Hi,
Let’s look at your error message:
Application Trace:
app/models/admin_user.rb:62:in `password_match?'
app/models/admin_user.rb:52:in `authenticate'
app/controllers/access_controller.rb:19:in `attempt_login'
You are correct that the original error is being triggered by the method attempt_login
in access_controller.rb.
However, when we inspect that, we see:
authorized_user = AdminUser.authenticate(params[:username], params[:password])
This line is calling the authenticate
method on your AdminUser
object.
The authenticate
method seems to be defined here: app/models/admin_user.rb:52
And this method is in turn calling the password_match?
method defined here: app/models/admin_user.rb:62
It is the password_match?
method that is triggering the error:
undefined local variable or method `salt' for #<AdminUser:0x41a6a68>
There could be a number of reasons for this happening.
Could you post the complete code from admin_user.rb and we’ll see if we can get to the bottom of it.
Thanks a lot, here is the complete admin_user.rb. I’m assuming I just made a foolish error somewhere, but I still cant seem to find out where:
require 'digest/sha1'
class AdminUser < ActiveRecord::Base
has_and_belongs_to_many :pages
has_many :section_edits
has_many :sections, :through => :section_edits
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i
validates :first_name, :presence => true, :length => { :maximum => 25 }
validates :last_name, :presence => true, :length => { :maximum => 50 }
validates :username, :length => { :within => 8..25 }, :uniqueness => true
validates :email, :presence => true, :length => { :maximum => 100 },
:format => EMAIL_REGEX, :confirmation => true
validates_length_of :password, :within => 8..25, :on => :create
before_save :create_hashed_password
after_save :clear_password
scope :named, lambda {|first,last| where(:first_name => first, :last_name => last)}
scope :sorted, order("admin_users.last_name ASC, admin_users.first_name ASC")
attr_protected :hashed_password, :salt
def name
"#{first_name} #{last_name}"
end
def self.authenticate(username="", password="")
user = AdminUser.find_by_username(username)
if user && user.password_match?(password)
return user
else
return false
end
end
def password_match?(password="")
hashed_password == AdminUser.hash_with_salt(password, salt)
end
def self.make_salt(username="")
Digest::SHA1.hexdigest("Use #{username} with #{Time.now} to make salt")
end
def self.hash_with_salt(password="", salt="")
Digest::SHA1.hexdigest("Put #{salt} on the #{password}")
end
private
def create_hashed_password
unless password.blank?
self.salt = AdminUser.make_salt(username) if salt.blank?
self.hashed_password = AdminUser.hash_with_salt(password, salt)
end
end
def clear_password
self.password = nil
end
end
It seems the error is being thrown by this line:
hashed_password == AdminUser.hash_with_salt(password, salt)
Do you have a “salt” field in your “adminusers” database table?
If so, are there any pending migrations that you have forgotten to carry out?
Failing those two things, what is your adminusers table structure?