Hi all,
I’m new to RoR, and I’ve only used regular expressions in bash, Java, and Perl. I am trying to validate a date input on my model, and I have the following line in my Item class.
validates_format_of( :purchase_date, :with => /\d{2}/\d{2}/\d{4}/, :message => " must be in the format dd/mm/yyyy")
Now, when I use the eclipse plugin QuickRex to get my regular expression, the string value “02/02/1997” matches my pattern. Do ruby regular expression not accept “\d” as a valid identifier for a number?
Thanks for the help guys. Every time I try this it fails. I'm giving
it the input of "02/02/1978" I've tried both of the following regular
expressions.
%r(^\d{2}\/\d{2}\/\d{4}$) and
/^\d{2}\/\d{2}\/\d{4}$/
Neither seems to work. Any ideas what's going on? I'm using Ruby
1.8.6, and Rails 1.2.3. Below is my entire model class, am I missing
something?
class Item < ActiveRecord::Base
belongs_to :channel;
validates_presence_of :name, :purchase_price, :purchase_date;
validates_numericality_of(:purchase_price, :message => " must me a
number");
validates_format_of( :purchase_date, :with => /^\d{2}\/\d{2}\/
\d{4}$/, :message => " must be in the format dd/mm/yyyy")
end
couple of SWAGs, since you don't say where input comes from: trailing
newline from somewhere in the chain, or you split on tabs and left
the tabs in the captured fields (tho i don't remember how to do this
in regexes)? encoding mismatch?
Hmmm. I'm not sure. The input just comes from a plain form post from
a form that's generated by rhtml, I don't format in any special way.
It won't pass validation in either Firefox or Safari. I thought that
perhaps I'd misspelled the field, but when I leave it blank it fails
the validates_presence_of check.
Fire up script/console and test your regex against a string (I
believe I clipped some IRB lines earlier for this regex). If it
succeeds, then instantiate your model:
a = Item.new(:name = 'a', :purchase_price => 3)
now
a.valid?
should be false because you didn't set the purchase date.
a.purchase_date = '02/02/78'
a.valid?
should be false because the year is in the wrong format.
a.purchase_date = '02/02/1978'
a.valid?
should be true because you've satisfied all your validations.
You could even write this in a test (which makes more sense in the
long run):
def items_should_validate_fields
a = Item.new(:name = 'a', :purchase_price => 3)
assert !a.valid?
# some assertion about what errors are reported
# and so on
end
Is purchase_date a date / datetime field in your database? if so then purchase_date will be an instance of Date or Time and those won't match a regular expression.
If you are validating an input in this way, the validation should be happening at the controller level: as far as the model concerned a date is just a date. Sure validate stuff like 'this date is not in the past' or 'this date can't be before this other date' but the sort of input validation you are doing doesn't belong there. If purchase_date is just a string , then that sounds wrong.
private
def validate
unless attributes_before_type_cast['date_of_loss'] =~ /^(\d+(-|\/)){2}\d{4}/
errors.add('date_of_loss', 'use the form: mm/dd/yyyy')
end
end
private
def validate
unless attributes_before_type_cast['date_of_loss'] =~ /^(\d+(-|
\/)){2}\d{4}/
errors.add('date_of_loss', 'use the form: mm/dd/yyyy')
end
end
This is a little wonky, as I believe the following irb session shows
So far so good. I've set my datetime column, and if i were to validate then the attribute before typecast is the string I supplied, and the format is ok.
So if you save and reload a valid record it becomes invalid: attributes_before_type_cast represents the string values that come out of the database, which will depend only on how your database formats dates, not what the user typed in.
Actually, that's the behavior I expect. The type *before type cast* is a string exactly as input. You are validating its format. The type after the cast is datetime and may not conform to your validation. But that's not where the data will be corrupted, right?
Actually, that's the behavior I expect. The type *before type cast*
is a string exactly as input. You are validating its format. The type
after the cast is datetime and may not conform to your validation.
But that's not where the data will be corrupted, right?
Well yes that's of course true, but it's deeply unhelpful if the
behaviour of your model
foo.valid?
=> true
foo.save
foo.reload
foo.valid?
=> false
Every time you or the user updates the record you'd have to coerce the
field to the pattern you wanted.
What you do in your validate method is up to you. It is extremely helpful that Rails automatically stores date/time values in a database native form where it can be sorted, used in criteria, etc. It may not be as helpful to you that the default implementation of Date#to_s produces an ISO date string. So, your validator could do something along the lines of:
private
def validate
# don't bother to validate if data was pulled from the database
if attributes_before_type_cast['date_of_loss'] == String
unless attributes_before_type_cast['date_of_loss'] =~ /^(\d+(-|\/)){2}\d{4}/
errors.add('date_of_loss', 'use the form: mm/dd/yyyy')
end
end
end