Marcin Grzesiek Fri Jun 17 06:21:16 -0400 2011

Subject: How To: Perform custom validation only on update

Hi,

I've created a custom validator and I want it run only on update, just like I can set it for predefined validators:

1 static $validates_presence_of = array(
2    array('title', 'message' => 'cannot be blank on a book!', 'on' => 'update')
3 );

I've tried to use

1 if ($this->is_new_record()) {
2 ...
3 }

in validator body, but it always returns true (maybe i misunderstood meaning of that method).

Any ideas ?


Daniel Lowrey Fri Jun 17 21:44:59 -0400 2011

You can accomplish what you want (or at least what I understand you to want) by using Model::is_new_record() in conjunction with Model::dirty_attributes()

Until a record is saved in the database, Model::is_new_record() will always return TRUE. So ...

 1 // A new record ..
 2 $m = new MyModel();
 3 echo $m->is_new_record() ? 'new record!' : 'NOT new';  // prints 'new record'
 4 
 5 // Save the model object then check again
 6 $m->my_property = 123;
 7 $m->save();
 8 echo $m->is_new_record() ? 'new record!' : 'NOT new';  // prints 'NOT new'
 9 
10 // Try it with an existing record
11 $m = MyModel::first();
12 echo $m->is_new_record() ? 'new record!' : 'NOT new';  // prints 'NOT new'

In contrast, Model::dirty_attributes() doesn't care if the record exists in the database or not. It only cares if the object has changed since the record was saved:

 1 // A new record ..
 2 $m = new MyModel();
 3 echo $m->dirty_attributes() ? 'DIRTY' : 'no changes';  // prints 'no changes'
 4 
 5 // Change a property value then try again
 6 $m->my_property = 456;
 7 echo $m->dirty_attributes() ? 'DIRTY' : 'no changes';  // prints 'DIRTY'
 8 
 9 // Try it with an existing record
10 $m = MyModel::first();
11 echo $m->is_new_record() ? 'new record!' : 'NOT new';  // prints 'NOT new'
12 echo $m->dirty_attributes() ? 'DIRTY' : 'no changes';  // prints 'no changes'
13 
14 // Change a property value then try again
15 $m->my_property = 789;
16 echo $m->is_new_record() ? 'new record!' : 'NOT new';  // prints 'NOT new'
17 echo $m->dirty_attributes() ? 'DIRTY' : 'no changes';  // prints 'DIRTY'
18 $m->save();
19 echo $m->dirty_attributes() ? 'DIRTY' : 'no changes';  // prints 'no changes'

So to only perform an action if a record is being updated in the database ...

1 $m = MyModel::find(123);
2 
3 // do some stuff here ...
4 
5 if ( ! $m->is_new_record() && $m->dirty_attributes()) {
6     // do something here
7 }
Marcin Grzesiek Sat Jun 18 04:08:13 -0400 2011

Thanks a lot for broad explanation. That's exactly what I wanted.

(1-2/2)