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:
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?
password
isn't a column in the database, right? Just an attribute?
So there is no password_changed?
method, which would be available if password
were a column. Rather you should just check to see if password
is set at all.
Something like:
validates :password_confirmation, :presence => true, :if => '!password.nil?'
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).
validates :password,
# you only need presence on create
:presence => { :on => :create },
# allow_nil for length (presence will handle it on create)
:length => { :minimum => 6, :allow_nil => true },
# and use confirmation to ensure they always match
:confirmation => true
If you've never seen :confirmation
before, it's a standard validation that looks for foo
and foo_confirmation
and makes sure they're the same.
Note that you still need to check for the presence of password_confirmation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With