# Different password validation on create and on update

**URL:** <https://www.ruby-forum.com/t/different-password-validation-on-create-and-on-update/140469>\
**Category:** Rails\
**Created:** [June 14, 2008, 3:19pm UTC](https://www.ruby-forum.com/t/different-password-validation-on-create-and-on-update/140469 "2008-06-14T15:19:33Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![taro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/df705f/32.png) [@taro](https://www.ruby-forum.com/u/taro)\
**Post date:** [June 14, 2008, 3:19pm UTC](https://www.ruby-forum.com/t/different-password-validation-on-create-and-on-update/140469/1 "2008-06-14T15:19:33Z")

</div>

I’ve got a model Officer that relies on password validation in all  
cases, but I need it to validate the password at different times. For  
on create, I want to verify that the password and password  
confirmation exists at all times. For update, want to make it  
possible for providing password optional, and only when the password  
is provided, to make sure it matches the password confirmation and the  
within a certain length (such as when calling method  
update\_attributes).

The best ways I see it right now is to define either  
before\_validation\_on\_create, after\_validation\_on\_create, or  
before\_create for method new, and define either  
before\_validation\_on\_update, after\_validation\_on\_update, or  
before\_update for method update\_attributes. It’s worth noting that  
Officer extends off of Person, which has it’s own validations to do.

I have several questions about this. First, which function should I  
define for validating create and update? What are the pros and cons  
on each one?  
I’ve also noticed that I cannot use validate\_length\_of and other  
helper methods inside these, and wondered why I’m not allowed to.  
Does this mean I have to make my own validation?  
If I do have to make my own validations within these methods, I will  
have to verify that the pseudo-parameters :password  
and :password\_confirmation exists. Do I have to call attr\_accessor on  
either :password, :password\_confirmation, or both in this case?

Many thanks in advance!

## P.S. Currently, my Officer and Person model looks like this:

class Officer \< Person  
#take care of password thingy  
validates\_length\_of :password, :within =\> 5…20  
#attr\_accessor :password\_confirmation  
validates\_presence\_of :password\_confirmation, :if =\> :password  
validates\_confirmation\_of :password

#some functions  
def validate  
errors.add\_to\_base(“Missing password”) if hashed\_password.blank?  
end

## def self.authenticate( rin, password ) person = self.find( :first, :conditions =\> [‘rin = ?’, rin] ) if person expected\_password = encrypted\_password( password, person.salt ) if person.hashed\_password != expected\_password person = nil end end person end end

class Person \< ActiveRecord::Base  
#first\_name is required: must start with a capital  
validates\_presence\_of :first\_name  
validates\_format\_of :first\_name,  
:with =\> /^[A-Z][a-zA-Z0-9, .]+$/

#last\_name is required: must start with a capital  
validates\_presence\_of :last\_name  
validates\_format\_of :last\_name,  
:with =\> /^[A-Z][a-zA-Z0-9, .]+$/

#rin is required: must be unique; also, must all be lowercases  
#with 0 to 2 numbers following the letters.  
validates\_presence\_of :rin,  
:message =\> ‘: A Rensselaer ID must be provided’  
validates\_format\_of :rin,  
:with =\> /^[a-z]+[0-9]{0,2}$/,  
:message =\> ‘: Invalid Rensselaer ID’  
validates\_uniqueness\_of :rin,  
:message =\> ‘: Someone already has this Rensselaer ID’

#email must be unique, and it is required.  
validates\_presence\_of :email  
validates\_format\_of :email,  
:with =\> /^[a-zA-Z0-9\_]+@[a-zA-Z0-9\_]+(.[a-z]{2,3}){1,2}$/  
validates\_uniqueness\_of :email

#year is required, and must be a 4 digit number greater than 2000  
validates\_presence\_of :year  
validates\_numericality\_of :year,  
:only\_integer =\> true  
validates\_length\_of :year,  
:is =\> 4

#completely ignore the passwords  
def password  
@password  
end

def password=(pwd)  
@password = pwd  
create\_new\_salt  
self.hashed\_password = Officer.encrypted\_password(self.password,  
self.salt)  
end

protected

def validate  
errors.add(:year, “should be between 2000 and 3000”) if  
( year.to\_i \< 2000 or year.to\_i \> 3000 )  
end

def self.encrypted\_password(password, salt)  
string\_to\_hash = password + “Japan is an island of interest” +  
salt  
Digest::SHA1.hexdigest(string\_to\_hash)  
end

def create\_new\_salt  
self.salt = (self.object\_id \* rand).to\_s + rand.to\_s  
end  
end

---

<div class="post-metadata">

**Author:** ![taro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/df705f/32.png) [@taro](https://www.ruby-forum.com/u/taro)\
**Post date:** [June 15, 2008, 6:17pm UTC](https://www.ruby-forum.com/t/different-password-validation-on-create-and-on-update/140469/2 "2008-06-15T18:17:31Z")

</div>

## I tried this:

class Officer \< Person  
#take care of password thingy  
attr\_accessor :password\_confirmation

#some functions I want to imitate for on\_create at all times,  
#and on\_update, only if password is not nil

#def validate

# errors.add\_to\_base(“Missing password”) if hashed\_password.blank?

#end

#validates\_presence\_of :password\_confirmation, :if =\> :password  
#validates\_confirmation\_of :password  
#validates\_length\_of :password, :within =\> 5…20

#functions that doesn’t work  
def before\_validation\_on\_create  
if @password.nil? or @password.empty?  
errors.add\_to\_base ‘You must provide a password’  
elsif @password.size \< 5 or @password.size \> 20  
errors.add\_to\_base ‘Password must be within 5 and 20 characters’  
end  
if @password\_confirmation.nil? or @password\_confirmation.empty?  
errors.add\_to\_base ‘You must provide a password confirmation’  
elsif @password\_confirmation != @password  
errors.add\_to\_base ‘Password does not match with Password  
Confirmation’  
end  
end

def before\_validation\_on\_update  
unless @password.nil?  
if @password.empty?  
errors.add\_to\_base ‘You must provide a password’  
elsif @password.size \< 5 or @password.size \> 20  
errors.add\_to\_base ‘Password must be within 5 and 20  
characters’  
end  
if @password\_confirmation.nil? or @password\_confirmation.empty?  
errors.add\_to\_base ‘You must provide a password confirmation’  
elsif @password\_confirmation != @password  
errors.add\_to\_base ‘Password does not match with Password  
Confirmation’  
end  
end  
end

#and functions that does  
def self.authenticate( rin, password )  
person = self.find( :first, :conditions =\> [‘rin = ?’, rin] )  
if person  
expected\_password = encrypted\_password( password, person.salt )  
if person.hashed\_password != expected\_password  
person = nil  
end  
end  
person  
end

#turns an Officer to Admin  
def turn\_to\_admin  
self.update\_attribute\_with\_validation\_skipping(:type, ‘Admin’)  
end

#This does nothing  
def turn\_to\_officer  
nil  
end

## #turns an Officer or Admin def turn\_to\_person self.update\_attribute\_with\_validation\_skipping(:type, ‘Person’) end end

## (Person.rb remains the same) But according to my unit tests, this doesn’t pass:

def test\_defective\_new  
officer = Officer.new( :first\_name =\> ‘John’,  
:last\_name =\> ‘Doe’, :rin =\> ‘doej’,  
:email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011,  
:password =\> ‘forka’)  
assert !officer.valid? #line 67, is not true  
assert !officer.errors.empty?  
end

def test\_empty\_password  
officer = Officer.new( :first\_name =\> ‘John’,  
:last\_name =\> ‘Doe’, :rin =\> ‘doej’,  
:email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011)  
assert !officer.valid? #line 12, is not true  
assert officer.errors.invalid?(:password)  
end

def test\_empty\_password\_confirmation  
officer = Officer.new( :first\_name =\> ‘John’,  
:last\_name =\> ‘Doe’, :rin =\> ‘doej’,  
:email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011,  
:password =\> ‘jojoj’, :password\_confirmation =\> ‘’)  
assert !officer.valid? #line 21, is not true  
assert officer.errors.invalid?(:password)  
end

def test\_password\_invalid\_confirmation  
officer = Officer.find(:first)  
assert officer  
officer[:password] = ‘testing’  
officer[:confirmation\_password] = ‘paco’  
officer.reload  
assert !officer.save #line 49, is not true  
end

def test\_password\_too\_short  
officer = Officer.new( :first\_name =\> ‘John’,  
:last\_name =\> ‘Doe’, :rin =\> ‘doej’,  
:email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011,  
:password =\> ‘jo’, :password\_confirmation =\> ‘jo’)  
assert !officer.valid? #line 39, is not true  
assert officer.errors.invalid?(:password)  
end

## def test\_unequal\_password\_confirmation officer = Officer.new( :first\_name =\> ‘John’, :last\_name =\> ‘Doe’, :rin =\> ‘doej’, :email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011, :password =\> ‘jojoj’, :password\_confirmation =\> ‘kkkkk’) assert !officer.valid? #line 30, is not true assert officer.errors.invalid?(:password) end

Loaded suite test/unit/officer\_test  
Started  
…FFFFFF.  
Finished in 0.438 seconds.

1. Failure:  
test\_defective\_new(OfficerTest)  
[test/unit/officer\_test.rb:67:in `test_defective_new' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

2. Failure:  
test\_empty\_password(OfficerTest)  
[test/unit/officer\_test.rb:12:in `test_empty_password' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

3. Failure:  
test\_empty\_password\_confirmation(OfficerTest)  
[test/unit/officer\_test.rb:21:in  
`test_empty_password_confirmation' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

4. Failure:  
test\_password\_invalid\_confirmation(OfficerTest)  
[test/unit/officer\_test.rb:49:in  
`test_password_invalid_confirmation' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

5. Failure:  
test\_password\_too\_short(OfficerTest)  
[test/unit/officer\_test.rb:39:in `test_password_too_short' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

6. Failure:  
test\_unequal\_password\_confirmation(OfficerTest)  
[test/unit/officer\_test.rb:30:in  
`test_unequal_password_confirmation' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

10 tests, 18 assertions, 6 failures, 0 errors

---

<div class="post-metadata">

**Author:** ![taro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/df705f/32.png) [@taro](https://www.ruby-forum.com/u/taro)\
**Post date:** [June 15, 2008, 6:33pm UTC](https://www.ruby-forum.com/t/different-password-validation-on-create-and-on-update/140469/3 "2008-06-15T18:33:27Z")

</div>

## I tried this:

class Officer \< Person  
#take care of password thingy  
attr\_accessor :password\_confirmation

#some functions I want to imitate for on\_create at all times,  
#and on\_update, only if password is not nil

#def validate

# errors.add\_to\_base(“Missing password”) if hashed\_password.blank?

#end

#validates\_presence\_of :password\_confirmation, :if =\> :password  
#validates\_confirmation\_of :password  
#validates\_length\_of :password, :within =\> 5…20

#functions that doesn’t work  
def before\_validation\_on\_create  
if @password.nil? or @password.empty?  
errors.add\_to\_base ‘You must provide a password’  
elsif @password.size \< 5 or @password.size \> 20  
errors.add\_to\_base ‘Password must be within 5 and 20 characters’  
end  
if @password\_confirmation.nil? or @password\_confirmation.empty?  
errors.add\_to\_base ‘You must provide a password confirmation’  
elsif @password\_confirmation != @password  
errors.add\_to\_base ‘Password does not match with Password  
Confirmation’  
end  
end

def before\_validation\_on\_update  
unless @password.nil?  
if @password.empty?  
errors.add\_to\_base ‘You must provide a password’  
elsif @password.size \< 5 or @password.size \> 20  
errors.add\_to\_base ‘Password must be within 5 and 20  
characters’  
end  
if @password\_confirmation.nil? or @password\_confirmation.empty?  
errors.add\_to\_base ‘You must provide a password confirmation’  
elsif @password\_confirmation != @password  
errors.add\_to\_base ‘Password does not match with Password  
Confirmation’  
end  
end  
end

#and functions that does  
def self.authenticate( rin, password )  
person = self.find( :first, :conditions =\> [‘rin = ?’, rin] )  
if person  
expected\_password = encrypted\_password( password, person.salt )  
if person.hashed\_password != expected\_password  
person = nil  
end  
end  
person  
end

#turns an Officer to Admin  
def turn\_to\_admin  
self.update\_attribute\_with\_validation\_skipping(:type, ‘Admin’)  
end

#This does nothing  
def turn\_to\_officer  
nil  
end

## #turns an Officer or Admin def turn\_to\_person self.update\_attribute\_with\_validation\_skipping(:type, ‘Person’) end end

## (Person.rb remains the same) But according to my unit tests, this doesn’t pass:

def test\_defective\_new  
officer = Officer.new( :first\_name =\> ‘John’,  
:last\_name =\> ‘Doe’, :rin =\> ‘doej’,  
:email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011,  
:password =\> ‘forka’)  
assert !officer.valid? #line 67, is not true  
assert !officer.errors.empty?  
end

def test\_empty\_password  
officer = Officer.new( :first\_name =\> ‘John’,  
:last\_name =\> ‘Doe’, :rin =\> ‘doej’,  
:email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011)  
assert !officer.valid? #line 12, is not true  
assert officer.errors.invalid?(:password)  
end

def test\_empty\_password\_confirmation  
officer = Officer.new( :first\_name =\> ‘John’,  
:last\_name =\> ‘Doe’, :rin =\> ‘doej’,  
:email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011,  
:password =\> ‘jojoj’, :password\_confirmation =\> ‘’)  
assert !officer.valid? #line 21, is not true  
assert officer.errors.invalid?(:password)  
end

def test\_password\_invalid\_confirmation  
officer = Officer.find(:first)  
assert officer  
officer[:password] = ‘testing’  
officer[:confirmation\_password] = ‘paco’  
officer.reload  
assert !officer.save #line 49, is not true  
end

def test\_password\_too\_short  
officer = Officer.new( :first\_name =\> ‘John’,  
:last\_name =\> ‘Doe’, :rin =\> ‘doej’,  
:email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011,  
:password =\> ‘jo’, :password\_confirmation =\> ‘jo’)  
assert !officer.valid? #line 39, is not true  
assert officer.errors.invalid?(:password)  
end

## def test\_unequal\_password\_confirmation officer = Officer.new( :first\_name =\> ‘John’, :last\_name =\> ‘Doe’, :rin =\> ‘doej’, :email =\> ‘removed\_email\_address@domain.invalid’, :year =\> 2011, :password =\> ‘jojoj’, :password\_confirmation =\> ‘kkkkk’) assert !officer.valid? #line 30, is not true assert officer.errors.invalid?(:password) end

Loaded suite test/unit/officer\_test  
Started  
…FFFFFF.  
Finished in 0.438 seconds.

1. Failure:  
test\_defective\_new(OfficerTest)  
[test/unit/officer\_test.rb:67:in `test_defective_new' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

2. Failure:  
test\_empty\_password(OfficerTest)  
[test/unit/officer\_test.rb:12:in `test_empty_password' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

3. Failure:  
test\_empty\_password\_confirmation(OfficerTest)  
[test/unit/officer\_test.rb:21:in  
`test_empty_password_confirmation' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

4. Failure:  
test\_password\_invalid\_confirmation(OfficerTest)  
[test/unit/officer\_test.rb:49:in  
`test_password_invalid_confirmation' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

5. Failure:  
test\_password\_too\_short(OfficerTest)  
[test/unit/officer\_test.rb:39:in `test_password_too_short' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

6. Failure:  
test\_unequal\_password\_confirmation(OfficerTest)  
[test/unit/officer\_test.rb:30:in  
`test_unequal_password_confirmation' c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2-/lib/ active_support/testing/default.rb:7:in`run’]:  
 is not true.

10 tests, 18 assertions, 6 failures, 0 errors

---

<div class="post-metadata">

**Author:** ![taro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/df705f/32.png) [@taro](https://www.ruby-forum.com/u/taro)\
**Post date:** [June 16, 2008, 3:18am UTC](https://www.ruby-forum.com/t/different-password-validation-on-create-and-on-update/140469/4 "2008-06-16T03:18:24Z")

</div>

> def validate
> 
> # this disallows empty values if the record is new
> 
> if self.new\_record? && (@pswd.blank? || @verify\_pswd.blank?)  
> self.errors.add(:pswd, ‘Password cannot be empty.’)  
> end
> 
> end  
> THIS is what I was looking for. The new\_record? method! Thanks you  
> so much!

By the way, I apologize for the triple post. They happened  
accidentally by the magic of F5 :-P.

---

<div class="post-metadata">

**Author:** ![taro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/df705f/32.png) [@taro](https://www.ruby-forum.com/u/taro)\
**Post date:** [June 15, 2008, 9:03pm UTC](https://www.ruby-forum.com/t/different-password-validation-on-create-and-on-update/140469/5 "2008-06-15T21:03:35Z")

</div>

> On Jun 14, 2008, at 6:18 AM, Taro wrote:
> 
> > 
> 
> For on create, I want to verify that the password and password  
> confirmation exists at all times. For update, want to make it  
> possible for providing password optional, and only when the password  
> is provided, to make sure it matches the password confirmation and the  
> within a certain length

Taro, 3 tips for validations:

(1) Have a look at these customized validation methods to help make  
validation code smaller and more readable for many scenarios:

[http://www.railsdev.ws/blog/11/custom-validations-in-rails/](http://www.railsdev.ws/blog/11/custom-validations-in-rails/)

(2) To validate a specific input only when it is not empty, use an  
:if =\> Proc.new technique. In my case, I use this for an email address  
like this:

validates\_as\_email :userEmail,  
:if =\> Proc.new { |PrivilegedUser|  
PrivilegedUser.userEmail.length \> 0 }

where :userEmail is the HTML input, and PrivilegedUser is the name  
of the class.

(3) For passwords, and other validations that require some custom logic,  
add a “validate” method to your class. ActiveRecord will call this  
automatically. Let’s assume your HTML inputs are pswd and verify\_pswd:

def validate

# this disallows empty values if the record is new

if self.new\_record? && (@pswd.blank? || @verify\_pswd.blank?)  
self.errors.add(:pswd, ‘Password cannot be empty.’)  
end

end

There are several waysto slice this as there are a few validation  
callbacks, so have a look here to see which one best suits how  
you prefer to organize your logic:

> **[ActiveRecord::Callbacks](https://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html)**
>
> Active Record Callbacks Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic before or after a change in the object state.

–  
def gw  
writes\_at ‘www.railsdev.ws’  
end
