aha,very nice!~
Ah, excellent, I was just struggling with this problem, and then your new post turned up in my rss feeds.
That last bit about passing false to the save method was really useful-seeming but I can't find anything in the API [official or caboo.se] that verifies that. Can you give a little more information about that? And does it work for create?
I have an additional question about conditional validation:
How do I only check one validation if an other validation returns true? For example, I would like to check the syntax of someones email address and I constructed a nice validator for this, but it doesn't check if the email field exists. Now I would only like to check the validity of the email syntax if the email field is even there. How can I do that?
Cristiano: Uses the option :allow_nil => true
Eg: validates_format_of :email, :allow_nil => true
This was new for me. It's amazing at how well thought out rails is.
Thanks again for the video Ryan.
@RSL, this is difficult to find in the documentation. The "save" method defined in ActiveRecord::Base doesn't accept a parameter. However, there is another method called save_with_validation which accepts a boolean. As it turns out, this method overrides the "save" method through alias_method_chain, so that is what is being called.
AFAIK it only applies to the "save" method, not the "create" method or any other method.
As always, great stuff!
I just looked at the Rdoc for validates_presence_of -- I noticed that the :if option can take a proc object. So maybe you could do something like this?
validates_presence_of :password,
:if => Proc.new { updating_password || new_record? }
Hmm, you might need to pass the user object into the block:
validates_presence_of :password, :if => Proc.new {|user| user.updating_password || user.new_record? }
True, the :if condition does take a Proc object, but I never use it because it's kind of ugly. Having it call a method is a much better solution IMO. It is cleaner, it is easier to extend and it can be shared across multiple validations.
For any Googlers or the curious out there, using this sort of conditional validation allows you to implement a multi-step creation process for a model. However, this sort of thing is VERY difficult to fit into the REST paradigm.
I think this episode was not good, because no real web-browser examples. :-( Only code.
I was looking for just something like this yesterday... well, sort of. I need to validate that a :start_date is before the :end_date. I didn't know about the :if => option on validations, so I wrote my own:
def validate
if self.start_date && self.end_date
errors.add( :end_date, "must be after the Start Date") if self.start_date > self.end_date
end
end
Probably not the cleanest method, but i works.
@Karl, sometimes you don't want to only change when a validation takes place, but the logic behind the validation as well. Rails offers various methods for setting validations (such as validates_presence_of), but I don't think there's any for comparing dates. In that case you did the right thing by making it a custom validation in the "validate" method.
Ryan, you are the best!
I was having problem with conditional validations just before you made this episode.
Thanks!
@Arthur:Geek: Thanx for the tip, but I don't want to allow for a nil, right? Or doesn't that matter because I also do the other check?
@Cristiano, I think what you want is an ":if" parameter as I show in the screencast. You would need to create a method to check if the email address is blank. Something like this:
--
validates_format_of ..., :if => :email_is_filled
def email_is_filled
!email.blank?
end
--
I don't think validates_format_of takes the allow_nil option, at least I don't see it in the docs.
Ryan, once again, I just wanted to continue to say good work and thanks for the insight.
This is cool. Makes me feel like a fool for previous over-complex solutions I implemented.
Very Nice!
Great as always, but I have a question: how do I set the @user.updating_password = true in functional test. I'm testing the changing password page =)
Oops. Sorry, that was a stupid question. I guess I'm getting tired.
Again - thanks for Railscasts!
Great stuff. Just what I needed when I needed it... Keep up the spot on tutorials!
@Ryan Bates
@ArthurGeek
Not only does validates_format_of not take the allow_nil option, it is also a known issue.
http://dev.rubyonrails.org/ticket/840
http://dev.rubyonrails.org/ticket/4208
allow_nil => true is a known method to make validations skip, to make way for validates_presence_of to kick in and put its error. But alas, it does not exist with validates_format_of ... and I have been trying to make my little rSpec pass for several days now with no success. Even the above patch did not help.
And you can find quite a bit of examples on the web where rail coders use this "missing" feature without being aware that its not there, because there is no warning or anything.
Another related problem is that rails will not convert empty strings into nil when posting forms, buts thats a whole other issue.
Ooops, seems that the mistake that prevented me from working (which I describe in the previous comment) was all my own.
Combined a spec for checking a nil email, with a too short email and a too long email into one specification - and thats what I get, errors and comments about the wrong things.
Because :allow_nil => true was at some point moved into validates_each, so now every validation that is using validates_each (most if not all of them) now has the allow_nil property.
Even though its not in the documentation - probably for historical reasons.
Greate tutorial
This was new for me. It's amazing at how well thought out rails is.
Thanks again for the video Ryan.
I am struggling with passing an argument to my condition method. what if your in_us? was in_country? that took a country name?
thanks a lot, really helped me a lot... thanks...


