On Wed, Feb 1, 2012 at 10:24 AM, sandip ransing <[email protected]>wrote:

> Hi Peter,
>
> validating date against Date.strptime('DATE STRING') will surely work.
> At controller level, i can able to do validation on date but at model
> level it goes for toss bcz value gets nil before validation(at assignment
> level)
>
> Would you please go through my previous reply.
>

OK, get it. I continue below.


>
>
> On Wed, Feb 1, 2012 at 2:43 PM, Peter Vandenabeele <[email protected]
> > wrote:
>
>> On Wed, Feb 1, 2012 at 9:22 AM, sandip ransing <[email protected]>wrote:
>>
>>>  consider scenario,
>>>
>>> User model with name, birth_date fields (here birth_date is not
>>> mandatory field)
>>>
>>> inside view form birth_date is assigned as '31/31/1985' which is invalid
>>>
>>> ideally user object should be invalid and while save raise an error on
>>> birth_date field but that's not happening and user object gets saved with
>>> birth_date as blank which is completely misleading.
>>>
>>
>> You are probably tripped up by the same unexpected behavior I recently
>> discovered.
>>
>> At least with Postgresql, if you assign a completely invalid string to a
>> date (or a datetime)
>> field, it does not  throw an exception but simply sets the value to nil:
>>
>> > c.birth_date = "2012-01-15"
>>  => "2012-01-15"
>> 1.9.3-p0 :011 > c.save!
>>    (0.2ms)  BEGIN
>>    (0.4ms)  UPDATE "children" SET "birth_date" = '2012-01-15',
>> "updated_at" = '2012-02-01 08:52:13.063755' WHERE "children"."id" = 1
>>    (8.5ms)  COMMIT
>>  => true
>> 1.9.3-p0 :012 > c.birth_date = "2012-01-45"
>>  => "2012-01-45"
>> 1.9.3-p0 :013 > c.save!
>>    (0.2ms)  BEGIN
>>    (0.4ms)  UPDATE "children" SET "birth_date" = NULL, "updated_at" = 
>> '2012-02-01
>> 08:54:46.965404' WHERE "children"."id" = 1
>>    (18.8ms)  COMMIT
>>  => true
>>
>> I would have expected an exception here as the POLS.
>>
>> But on 'true' it does raise an exception (I discovered this
>> because Rails.logger.warning now returns true).
>>
>> c.birth_date = true
>>  => true
>> 1.9.3-p0 :015 > c.save!
>>    (0.2ms)  BEGIN
>>    (0.4ms)  UPDATE "children" SET "birth_date" = 't', "updated_at" = 
>> '2012-02-01
>> 08:56:00.771141' WHERE "children"."id" = 1
>> PGError: ERROR:  invalid input syntax for type date: "t"
>> LINE 1: UPDATE "children" SET "birth_date" = 't', "updated_at" = '20...
>>                                              ^
>> : UPDATE "children" SET "birth_date" = 't', "updated_at" = '2012-02-01 
>> 08:56:00.771141'
>> WHERE "children"."id" = 1
>>    (0.2ms)  ROLLBACK
>> ActiveRecord::StatementInvalid: PGError: ERROR:  invalid input syntax for
>> type date: "t"
>>
>>
>> After debugging found that while assigning attributes birth_date value it
>>> gets assigned as blank and as birth_date is optional object gets saved.
>>>
>>> class User < ActiveRecord::Base
>>>
>>>
>>>   def initialize(args={})
>>>     logger.info args[:birth_date] #invalid value comes upto here but 
>>> vanishes afterwords
>>>
>>>
>>>
>>>
>>>
>>>     super
>>>   end
>>> end
>>>
>>> Any clue how to get validation working properly for not mandatory date 
>>> fields ??
>>>
>>>
>> As for the validation. You could use a regex, as suggested by Neethu, but
>> that has the limitation
>> that it is hard do calculate that 2012-01-29 is OK en 2013-01-29 is not
>> OK.
>>
>> Better may be to use a combination of strptime and rescue ArgumentError
>>
>>
>> 1.9.3-p0 :051 > begin
>> 1.9.3-p0 :052 >     Date.strptime("29/02/2012", "%d/%m/%Y")
>> 1.9.3-p0 :053?>   rescue ArgumentError
>> 1.9.3-p0 :054?>   puts "This date is invalid"
>> 1.9.3-p0 :055?>   end
>>  => Wed, 29 Feb 2012
>>
>> 1.9.3-p0 :056 > begin
>> 1.9.3-p0 :057 >     Date.strptime("2012-31-31", "%Y-%m-%d")
>> 1.9.3-p0 :058?>   rescue ArgumentError
>> 1.9.3-p0 :059?>   puts "This date is invalid"
>> 1.9.3-p0 :060?>   end
>> This date is invalid
>>  => nil #This comes from the last line in the rescue block, which is puts
>> here
>>
>> 1.9.3-p0 :061 > begin
>> 1.9.3-p0 :062 >     Date.strptime("10/01/2012", "%d/%m/%Y")
>> 1.9.3-p0 :063?>   rescue ArgumentError
>> 1.9.3-p0 :064?>   puts "This date is invalid"
>> 1.9.3-p0 :065?>   end
>>  => Tue, 10 Jan 2012  # Correct EU dd/mm/yyyy intepretation
>>
>> 1.9.3-p0 :066 > begin
>> 1.9.3-p0 :067 >     Date.strptime("10/01/2012", "%m/%d/%Y")
>> 1.9.3-p0 :068?>   rescue ArgumentError
>> 1.9.3-p0 :069?>   puts "This date is invalid"
>> 1.9.3-p0 :070?>   end
>>  => Mon, 01 Oct 2012 # Correct US mm/dd/yyyy interpretation
>>
>>

With setting an error then:

u = User.new
u.birth_date = '31/31/2011'
u.birth_date #=> nil
u.valid? #=> true

u.birth_date = '1/1/2011'
u.birth_date #=> Sat, 01 Jan 2011


UNTESTED:
ONLY WORKs in Rails 3.2.x

birth_date = is overriden and call the original birth_date = with a
properly parsed Date object

my_parsed_date will set an error if the parsing failed,
so you object is not longer valid.

NOT TESTED, but indicative of a style.

class User

  def birth_date=(bd)
    super(my_parsed_date(bd, :birth_date))
  end

end


# this function could go in a library somewhere
def my_parsed_date(bd, attr)
  begin
    Date.strptime(bd, "%m/%d/%Y")
  rescue ArgumentError
    self.errors.add(attr, "date is invalid")
    nil # this will be returned upon rescue
  end
end


HTH,

Peter

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en.

Reply via email to