Hi all, Is there a way to invoke validations at times other than save, create and update? I know that I can do this by writing my own validation checks using errors.add_[blah], but I''d like to leverage the existing validation code. What I have is two sets of fields in a record, set A and set B. Both sets must be validated on record create. However, the trouble is that after create, fields from both of these sets can be changed, and changed independently (so I can''t just restrict set B to validations on create). The trouble is that set B contains items such as a password that is encrypted via a before_create filter, so it will fail validations after that, assuming that it is not being recreated. I can think of some other possibilities, e.g. using update_attribute in methods that operate on the sets independently, but I''d rather avoid multiple record saves. Thanks! Joe
Okay, an update - here''s something that works for me, assuming that there are no validations tagged with :on => :create other than the ones that I want to selectively (which is obviously a problem if someone inherits from or extends this class). So, I''m still looking for something functionally equivalent if there are any sugggestions. I guess it''d be nice if there were something like an option such as :on => :manual for the validations. Thanks! - Joe before_validate_on_create :setup_validations before_save :do_stuff def setup_validations @doit = true end def do_stuff if @do_it # Wait for the next time this is set and we must do the validations on update @do_it = false if not new_record? run_validations(:validate_on_create) validate_on_create return false if not errors.empty? end write_attribute(blah, ) end On Apr 23, 2005, at 4:16 PM, Joseph Hosteny wrote:> Hi all, > > Is there a way to invoke validations at times other than save, create > and update? I know that I can do this by writing my own validation > checks using errors.add_[blah], but I''d like to leverage the existing > validation code. > > What I have is two sets of fields in a record, set A and set B. Both > sets must be validated on record create. However, the trouble is that > after create, fields from both of these sets can be changed, and > changed independently (so I can''t just restrict set B to validations > on create). The trouble is that set B contains items such as a > password that is encrypted via a before_create filter, so it will fail > validations after that, assuming that it is not being recreated. > > I can think of some other possibilities, e.g. using update_attribute > in methods that operate on the sets independently, but I''d rather > avoid multiple record saves. > > Thanks! > Joe > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Yo can call validations at any time explicitely with `valid?` member: something like: person.valid? Zsombor On 4/23/05, Joseph Hosteny <jhosteny-ee4meeAH724@public.gmane.org> wrote:> Okay, an update - here''s something that works for me, assuming that > there are no validations tagged with :on => :create other than the ones > that I want to selectively (which is obviously a problem if someone > inherits from or extends this class). So, I''m still looking for > something functionally equivalent if there are any sugggestions. > > I guess it''d be nice if there were something like an option such as :on > => :manual for the validations. > > Thanks! - Joe > > before_validate_on_create :setup_validations > before_save :do_stuff > > def setup_validations > @doit = true > end > > def do_stuff > if @do_it > # Wait for the next time this is set and we must do the validations > on update > @do_it = false > > if not new_record? > run_validations(:validate_on_create) > validate_on_create > return false if not errors.empty? > end > > write_attribute(blah, ) > end > > On Apr 23, 2005, at 4:16 PM, Joseph Hosteny wrote: > > > Hi all, > > > > Is there a way to invoke validations at times other than save, create > > and update? I know that I can do this by writing my own validation > > checks using errors.add_[blah], but I''d like to leverage the existing > > validation code. > > > > What I have is two sets of fields in a record, set A and set B. Both > > sets must be validated on record create. However, the trouble is that > > after create, fields from both of these sets can be changed, and > > changed independently (so I can''t just restrict set B to validations > > on create). The trouble is that set B contains items such as a > > password that is encrypted via a before_create filter, so it will fail > > validations after that, assuming that it is not being recreated. > > > > I can think of some other possibilities, e.g. using update_attribute > > in methods that operate on the sets independently, but I''d rather > > avoid multiple record saves. > > > > Thanks! > > Joe > > > > _______________________________________________ > > Rails mailing list > > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- http://deezsombor.blogspot.com
The problem with that is that if the call is made sometime after the record is created, the only way to get the desired validations to run when calling valid? is to mark them with :on => update (or :save). The trouble is that I don''t want to have them *always* run during updates. I realize I can do this via an override of one of the validate_on_* calls, and implement a check in that function before running error.add_on_* calls, but I''d like to leverage the included validations and error messages. Here''s what I ultimately came to yesterday. Note '':on => :manual'' attribute setting in the hash after the class validation. Included prior to my model: ActiveRecord::Validations::ClassMethods.module_eval { def validate_on_manual(*methods, &block) methods << block if block_given? write_inheritable_set(:validate_on_manual, methods) end private def validation_method(on) case on when :save then :validate when :create then :validate_on_create when :update then :validate_on_update when :manual then :validate_on_manual end end } class MyModel < ActiveRecord::Base before_validation_on_create :setup_validations before_save :do_stuff def setup_validations @do_it = true end def do_stuff if @do_it # Wait for the next time we are told to do this @encrypt = false write_attribute(''some_attribute'', ...) end end def valid? return false if super == false run_validations(:validate_on_manual) if @doit return errors.empty? end validates_presence_of :some_attribute, :on => :manual end On Apr 24, 2005, at 8:33 AM, Dee Zsombor wrote:> Yo can call validations at any time explicitely with `valid?` member: > something like: > > person.valid? > > Zsombor > > On 4/23/05, Joseph Hosteny <jhosteny-ee4meeAH724@public.gmane.org> wrote: >> Okay, an update - here''s something that works for me, assuming that >> there are no validations tagged with :on => :create other than the >> ones >> that I want to selectively (which is obviously a problem if someone >> inherits from or extends this class). So, I''m still looking for >> something functionally equivalent if there are any sugggestions. >> >> I guess it''d be nice if there were something like an option such as >> :on >> => :manual for the validations. >> >> Thanks! - Joe >> >> before_validate_on_create :setup_validations >> before_save :do_stuff >> >> def setup_validations >> @doit = true >> end >> >> def do_stuff >> if @do_it >> # Wait for the next time this is set and we must do >> the validations >> on update >> @do_it = false >> >> if not new_record? >> run_validations(:validate_on_create) >> validate_on_create >> return false if not errors.empty? >> end >> >> write_attribute(blah, ) >> end >> >> On Apr 23, 2005, at 4:16 PM, Joseph Hosteny wrote: >> >>> Hi all, >>> >>> Is there a way to invoke validations at times other than save, >>> create >>> and update? I know that I can do this by writing my own validation >>> checks using errors.add_[blah], but I''d like to leverage the existing >>> validation code. >>> >>> What I have is two sets of fields in a record, set A and set >>> B. Both >>> sets must be validated on record create. However, the trouble is that >>> after create, fields from both of these sets can be changed, and >>> changed independently (so I can''t just restrict set B to validations >>> on create). The trouble is that set B contains items such as a >>> password that is encrypted via a before_create filter, so it will >>> fail >>> validations after that, assuming that it is not being recreated. >>> >>> I can think of some other possibilities, e.g. using >>> update_attribute >>> in methods that operate on the sets independently, but I''d rather >>> avoid multiple record saves. >>> >>> Thanks! >>> Joe >>> >>> _______________________________________________ >>> Rails mailing list >>> Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >>> http://lists.rubyonrails.org/mailman/listinfo/rails >>> >> >> _______________________________________________ >> Rails mailing list >> Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >> http://lists.rubyonrails.org/mailman/listinfo/rails >> > > > -- > http://deezsombor.blogspot.com > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
> def valid? > return false if super == false > run_validations(:validate_on_manual) if @doit > return errors.empty? > endWhile I dont understand why would you wish to skipp validations at all, I believe that this will always run validations once and under certain circumsances a second time under also.
Dee, Specifically, I''m using it to skip validation of an encrypted password. If the password is only written on create, then none of this is needed (just use :on => :create). But the validation checks the unencrypted password and password confirmation during updates as well, since I want to be able to support changing passwords. Obviously, though, the record changes state at times other than when the password is changed. I could make the validation handle the encrypted password as well, but I''d prefer it be clear that it is checking the unencrypted password. I''m probably nitpicking too much :) Part of this is just a learning experience for me too, so I''m trying to get an idea of best practices in the rails code for what I''m trying to do. There are certainly lots of ways to get what I want, I''m just feeling the code out and trying to find something simple and readable. Thanks for your feedback! Joe On Apr 24, 2005, at 12:53 PM, Dee Zsombor wrote:>> def valid? >> return false if super == false >> run_validations(:validate_on_manual) if @doit >> return errors.empty? >> end > > While I dont understand why would you wish to skipp validations at > all, I believe that this will always run validations once and under > certain circumsances a second time under also. > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
On 4/24/05, Joseph Hosteny <jhosteny-ee4meeAH724@public.gmane.org> wrote:> Dee, > > Specifically, I''m using it to skip validation of an encrypted password. > If the password is only written on create, then none of this is needed > (just use :on => :create). But the validation checks the unencrypted > password and password confirmation during updates as well, since I want > to be able to support changing passwords. Obviously, though, the record > changes state at times other than when the password is changed. > > I could make the validation handle the encrypted password as well, but > I''d prefer it be clear that it is checking the unencrypted password. > I''m probably nitpicking too much :) > > Part of this is just a learning experience for me too, so I''m trying to > get an idea of best practices in the rails code for what I''m trying to > do. There are certainly lots of ways to get what I want, I''m just > feeling the code out and trying to find something simple and readable. > > Thanks for your feedback! > > JoeJoe, I am unsure if this is the ''best'' way to approach this problem, but here''s how I dealt with it in my User class (with unrelated stuff snipped out): class User < ActiveRecord::Base validates_confirmation_of :password attr_protected :password_hash after_validation :write_password_hash #The following 4 methods would likely be much better off implemented using the attr_ #meta methods, but oh well... def password=(new_pass) @password = new_pass end def password_confirmation=(confirmation) @password_confirmation = confirmation end def password @password end def password_confirmation @password_confirmation end def has_password? self.password_hash.nil? end private def self.hash_password(password) Digest::MD5.hexdigest(password) end def write_password_hash if !@password.nil? and errors.on?(''password'').nil? write_attribute("password_hash", self.class.hash_password(@password)) end end end Essentially, I have a password_hash field in my table, but _no_ password field. I made a ''virtual'' password field that AR can interact with to validate confirmation, etc. Then, when the record is written, if the virtual ''password'' field has anything in it and has been validated, I write the hash of that password to the db. Works rather well, for me. Dave -- Dave Goodlad dgoodlad-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org or dave-eHfbeeWWzZOw5LPnMra/2Q@public.gmane.org http://david.goodlad.ca/
David- thanks, I wound up doing just that. I''m not sure why I didn''t in the first place. For some reason, I wanted to clear out the passwords from the object once they''d been written to the DB, but I can''t seem to remember why. This works just fine. Joe On Apr 24, 2005, at 3:49 PM, David Goodlad wrote:> On 4/24/05, Joseph Hosteny <jhosteny-ee4meeAH724@public.gmane.org> wrote: >> Dee, >> >> Specifically, I''m using it to skip validation of an encrypted >> password. >> If the password is only written on create, then none of this is needed >> (just use :on => :create). But the validation checks the unencrypted >> password and password confirmation during updates as well, since I >> want >> to be able to support changing passwords. Obviously, though, the >> record >> changes state at times other than when the password is changed. >> >> I could make the validation handle the encrypted password as well, but >> I''d prefer it be clear that it is checking the unencrypted password. >> I''m probably nitpicking too much :) >> >> Part of this is just a learning experience for me too, so I''m trying >> to >> get an idea of best practices in the rails code for what I''m trying to >> do. There are certainly lots of ways to get what I want, I''m just >> feeling the code out and trying to find something simple and readable. >> >> Thanks for your feedback! >> >> Joe > > Joe, > > I am unsure if this is the ''best'' way to approach this problem, but > here''s how I dealt with it in my User class (with unrelated stuff > snipped out): > > class User < ActiveRecord::Base > validates_confirmation_of :password > attr_protected :password_hash > after_validation :write_password_hash > > #The following 4 methods would likely be much better off implemented > using the attr_ > #meta methods, but oh well... > def password=(new_pass) > @password = new_pass > end > def password_confirmation=(confirmation) > @password_confirmation = confirmation > end > def password > @password > end > def password_confirmation > @password_confirmation > end > > def has_password? > self.password_hash.nil? > end > > private > def self.hash_password(password) > Digest::MD5.hexdigest(password) > end > > def write_password_hash > if !@password.nil? and errors.on?(''password'').nil? > write_attribute("password_hash", > self.class.hash_password(@password)) > end > end > end > > Essentially, I have a password_hash field in my table, but _no_ > password field. I made a ''virtual'' password field that AR can > interact with to validate confirmation, etc. Then, when the record is > written, if the virtual ''password'' field has anything in it and has > been validated, I write the hash of that password to the db. Works > rather well, for me. > > Dave > > -- > Dave Goodlad > dgoodlad-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org or dave-eHfbeeWWzZOw5LPnMra/2Q@public.gmane.org > http://david.goodlad.ca/ > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >