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,
Todd
irb(main):006:0> ‘02/15/2008’ =~ /\d{2}/\d{2}/\d{4}/
=> 0
irb(main):007:0> ‘02/15/08’ =~ /\d{2}/\d{2}/\d{4}/
=> nil
So the first expression matched at position zero, the second one
didn’t match at all. I don’t see a problem with \d.
On 10/13/07, s.ross [email protected] wrote:
On Oct 13, 2007, at 5:48 PM, Todd N. wrote:
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")
As s.ross pointed out this should work.
OP, Did you try it? You didn’t actually say you did.
Also, note that this will also validate things like:
“My cat’s name is fluffy he was born on 12/12/2003, isn’t he cute?”
You should anchor the regexp i.e.
/^\d{2}/\d{2}/\d{4}$/
You can also get rid of a few of the “leaning toothpicks” by using %r
instead of / to delimit the regexp:
%r(^\d{2}/\d{2}/\d{4})
–
Rick DeNatale
My blog on Ruby
http://talklikeaduck.denhaven2.com/
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
Thanks,
Todd
On 10/14/07, Rick DeNatale [email protected] wrote:
%r(^\d{2}/\d{2}/\d{4})
Oops, left off the end anchor on that last:
%r(^\d{2}/\d{2}/\d{4}$)
–
Rick DeNatale
My blog on Ruby
http://talklikeaduck.denhaven2.com/
On Oct 16, 6:18 pm, Todd N. [email protected] wrote:
Thanks,
Todd
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?
BTW generally preferred not to top-post.
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
Hope this helps.
On 17 Oct 2007, at 03:56, Todd N. wrote:
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.
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.
Fred
On Oct 17, 2007, at 1:52 AM, Frederick C. wrote:
the validates_presence_of check.
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.
At the model level, this works:
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
My field was ‘date_of_loss’. Fill in your own.
On Oct 17, 2007, at 12:38 PM, Frederick C. wrote:
def validate
=> “10/31/2007”
r.comment_read_at
=> Wed Oct 31 00:00:00 UTC 2007
r.comment_read_at_before_type_cast
=> “10/31/2007”
r.valid?
=> true
r.save
=> true
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?
On 17 Oct 2007, at 18:58, s.ross wrote:
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
r.comment_read_at = ‘10/31/2007’
=> “10/31/2007”
r.comment_read_at
=> Wed Oct 31 00:00:00 UTC 2007
r.comment_read_at_before_type_cast
=> “10/31/2007”
r.valid?
=> true
r.save
=> true
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.
r.reload
[snip]
r.comment_read_at
=> Wed Oct 31 00:00:00 UTC 2007
r.comment_read_at_before_type_cast
=> “2007-10-31 00:00:00”
r.valid?
=> false
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.
Fred
On Oct 18, 2007, at 12:40 AM, Frederick C. wrote:
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.
Fred
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
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.
Fred