I’ve got the following User model:
class User < ActiveRecord::Base
# Users table has the necessary password_digest field
has_secure_password
attr_accessible :login_name, :password, :password_confirmation
validates :login_name, :presence=>true, :uniqueness=>true
# I run this validation on :create so that user
# can edit login_name without having to enter password
validates :password,:presence=>true,:length=>{:minimum=>6},:on=>:create
# this should only run if the password has changed
validates :password_confirmation,
:presence=>true, :if => :password_digest_changed?
end
These validations don’t quite do what I was hoping they would. It’s possible to do the following:
# rails console
u = User.new :login_name=>"stephen"
u.valid?
# => false
u.errors
# => :password_digest=>["can't be blank"],
# => :password=>["can't be blank", "please enter at least 6 characters"]}
# so far so good, let's give it a password and a valid confirmation
u.password="password"
u.password_confirmation="password"
# at this point the record is valid and does save
u.save
# => true
# but we can now submit a blank password from console
u.password=""
# => true
u.password_confirmation=""
# => true
u.save
# => true
# oh noes
So what I want is the following:
- password required on create, must be 6 chars in long
- password_confirmation required on create, must match password
- user should not have to submit password when updating login_name
- password can not be deleted on update
Something which is confusing me is that rails throws a no method error if I use password_changed? as opposed to :password_digest_changed? in my password_confirmation validation. I don’t understand why.
So does anyone know what I’m doing wrong here?
passwordisn’t a column in the database, right? Just an attribute?So there is no
password_changed?method, which would be available ifpasswordwere a column. Rather you should just check to see ifpasswordis set at all.Something like:
Although that solves the initial problem you were having, it still won’t quite do what you want, as it’s only checking presence, and you need it to be present and match password. Something like the following should work (in combination with the above validation).
If you’ve never seen
:confirmationbefore, it’s a standard validation that looks forfooandfoo_confirmationand makes sure they’re the same.Note that you still need to check for the presence of
password_confirmation