How to skip password validation when updating other fields?


#1

Besides the hashed password, which is saved to db, I have two
password-attributes in my User model:

attr_accessor :password, :password_confirmation

I have validations on these attributes, and I need them to work both on
create and update, since I have pages for changing and resetting the
password.

Now when I want to update just the user’s login name, I guess I have the
next options:

user = User.find(session[:user_id])
user.login = params[:login]
user.save
=> Won’t work because the password and password_confirmation validations
hit.

user = User.find(session[:user_id])
user.login = params[:login]
user.update_attributes(:login => params[:login] )
=> Won’t work because the password and password_confirmation validations
hit.

user = User.find(session[:user_id])
user.login = params[:login]
user.update_attribute(:login, params[:login] )
=> Updates the fiels to db, but passes all validations. Now I think it’s
bad idea to do the validations every time in the controller when I need
to update a field.

user = User.find(session[:user_id])
user.login = params[:login]
if user.valid?
user.update_attribute(:login, params[:login] )
end
=> Won’t work because the password and password_confirmation validations
hit.

Is there any way to skip the validations for the password attributes?

I’ve been thinkin of creating validation method in the user model, that
skips the password-fields like this:

def validate_all_but_password
loop through validations
if the validation name doesn’t equal ‘password’ or
‘password_confirmation’
run the validation

and then call it before update_attribute.

What do you think, would this be a good practise, or is there another
way to solve this problem?


#2

If I just had surfed to the api doc before posting… heh

Found the solution, added this on the validations of password:

:if => :validate_password

then before I call user.save I call user.dont_validate_password, which
sets instance variable to false and the validate_password method then
returns false.


#3

How about specifying that the validation only be performed upon model
creation?

E.g. validates_confirmation_of :password, :password_confirmation, :on =>
:create


#4

Don Walker wrote:

How about specifying that the validation only be performed upon model
creation?

E.g. validates_confirmation_of :password, :password_confirmation, :on =>
:create

But I need to validate the input also when the user updates the
password.


#5

Basically, you just have to look at the before_create and before_save
methods.

Here’s what I do… Password field is validated on create only.
Password is set on update only if the password field is not nil.

class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :username, :password, :email
validates_uniqueness_of :username, :email
validates_presence_of :username, :email
has_and_belongs_to_many :machines

def validate_on_create
errors.add_to_base(“Password field must not be left blank!”) if
self.password == “” or self.password.nil?
end

hash the password for storage in the DB

def before_create
self.hashed_password = User.hash_password(self.password)
end

hash the password before updating but only if the password field is

actually filled in.
def before_update()
unless self.password.nil?
self.password = User.hash_password(self.password)
end
end

def after_create
self.password = nil
end

end


#6

You could do it this way in your model…

validates_presence_of :password, :if => :password_required?
validates_confirmation_of :password, :if => :password_required?

where…

protected
def password_required?
hashed_password.blank? or not password.blank?
end