Hi, I would like to validate a date (29 feb 2005 is invalid) and if it is an invalid date display an error to the user, using the default way of displaying errors. In my view I have a simple date_select: <%= date_select (:listing, :start_date, {:order => [:day, :month, :year], :start_year => Time.now.year, :end_year => Time.now.year+1}) %> When I save data to the db, the field start_date should be validated and if their is an error display it. So in my model I have tried: def validate_on_create year = start_date(1i) month = start_date(2i) day = start_date(3i) unless Date::valid_date?(year.to_i, month.to_i, day.to_i) errors.add(:start_date, "De startdatum moet een geldige datum zijn.") end end But this doesn''t work, because I can''t access the values inside start_date in the model. I get errors like that start_date is multiparameter . I know that, but I can''t get to the values of the parameters. Hope somebody can help. Kind regards, Nick -- Posted via http://www.ruby-forum.com/.
Nick Snels wrote:> Hi, > > I would like to validate a date (29 feb 2005 is invalid) and if it is an > invalid date display an error to the user, using the default way of > displaying errors. In my view I have a simple date_select: > > <%= date_select (:listing, :start_date, > {:order => [:day, :month, :year], > :start_year => Time.now.year, > :end_year => Time.now.year+1}) %> > > When I save data to the db, the field start_date should be validated and > if their is an error display it. So in my model I have tried: > > def validate_on_create > year = start_date(1i) > month = start_date(2i) > day = start_date(3i) > unless Date::valid_date?(year.to_i, month.to_i, day.to_i) > errors.add(:start_date, "De startdatum moet een geldige datum > zijn.") > end > end > > But this doesn''t work, because I can''t access the values inside > start_date in the model. I get errors like that start_date is > multiparameter . I know that, but I can''t get to the values of the > parameters. Hope somebody can help.Nick, applying posted parameters to your model using new, attributes=, update_attributes, etc., will automatically set start_date to an object of type Date based on the three component parameters. If the date is invalid I think start_date will be set to nil, for which you can check. If that''s not enough control, you''ll have to either arrange to give validate_on_create access to the params hash so you can check the values of the start_date(<n>i) keys, or do the validation in a separate date validation method called from the controller. I wonder what the value of start_date.before_type_cast would be? It''d be nice if this was a three-element array for easy validation. -- We develop, watch us RoR, in numbers too big to ignore.
On Dec 3, 2005, at 2:09 PM, Nick Snels wrote:> Hi, > > I would like to validate a date (29 feb 2005 is invalid) and if it > is an > invalid date display an error to the user, using the default way of > displaying errors. In my view I have a simple date_select: > > <%= date_select (:listing, :start_date, > {:order => [:day, :month, :year], > :start_year => Time.now.year, > :end_year => Time.now.year+1}) %> > > When I save data to the db, the field start_date should be > validated and > if their is an error display it. So in my model I have tried: > > def validate_on_create > year = start_date(1i) > month = start_date(2i) > day = start_date(3i) > unless Date::valid_date?(year.to_i, month.to_i, day.to_i) > errors.add(:start_date, "De startdatum moet een geldige datum > zijn.") > end > end > > But this doesn''t work, because I can''t access the values inside > start_date in the model. I get errors like that start_date is > multiparameter . I know that, but I can''t get to the values of the > parameters. Hope somebody can help. > > Kind regards, > > NickI don''t know if this helps, but we''re validating the expiration date of a credit card this way: require ''Date'' validates_each :payment_mm do |m, a, month| if ((month.to_i < DateTime.now.month) && (m.payment_yyyy.to_i == DateTime.now.year)) m.errors.add(a, "Your credit card seems to be expired. Please enter valid payment information.") end end Also, remember that if you operate on an instance''s values, you need to refer to ''self''. E.g., in the same model we send the order email and then clear the credit card number before saving: def before_save OrderMailer.deliver_order(self) self.payment_account="(not recorded)" end Phil
Hi, thank you both for the command. Helped to clear some issues up. I have simplified my model code to, just to see the effect of the date: def validate logger.warn ("Start-- " + start_date.to_s) end I get a date back when I enter a valid date. But when I enter an invalid date I get the error: 1 error(s) on assignment of multiparameter attributes I have tried to catch the error like this: def validate begin unless self.start_date errors.add(:start_date, "De startdatum moet een geldige datum zijn.") end rescue errors.add(:start_date, "De startdatum moet een geldige datum zijn.") end end But I keep getting the error. The error obviously means the date I entered cann''t get converted to a valid date. So if I can catch this error I''m done. But ... Kind regards, Nick -- Posted via http://www.ruby-forum.com/.
Getting tired of all the error messages, I thought I would throw the date_select away in favor of: <%= select_day (Time.now.day, :prefix => "listing") %> <%= select_month (Time.now.month, :prefix => "listing") %> <%= select_year (Time.now.year, :prefix => "listing", :start_year => Time.now.year, :end_year => Time.now.year+1) %> Generates the same HTML code and now I get three separate params, not related to each other, so no more multiparameter stuff. I my model I added: attr_accessor :day, :month, :year def validate if Date::valid_civil?(year.to_i, month.to_i, day.to_i) == nil errors.add(:year, "geen geldige datum.") else self.start_date = year.to_s + "-" + month.to_s + "-" + day.to_s end end So now I should also be able to check if the date is before today. Only problem I have right now is I can''t get Rails to draw a red box around my three select fields (day, month and year). But if that is all, at least my visitors are no longer able to enter an invalid date. My advice stay away from date_select if you want to do some serious date checking, at least until they introduce a decent date validator, like validate_date_of or something like that. Kind regards, Nick -- Posted via http://www.ruby-forum.com/.
ara.t.howard-32lpuo7BZBA@public.gmane.org
2005-Dec-04 19:11 UTC
Re: How to validate a date
On Sat, 3 Dec 2005, Nick Snels wrote:> I would like to validate a date (29 feb 2005 is invalid) and if it is an > invalid date display an error to the user, using the default way of > displaying errors. In my view I have a simple date_select: > > <%= date_select (:listing, :start_date, > {:order => [:day, :month, :year], > :start_year => Time.now.year, > :end_year => Time.now.year+1}) %> > > When I save data to the db, the field start_date should be validated and if > their is an error display it. So in my model I have tried: > > def validate_on_create > year = start_date(1i) > month = start_date(2i) > day = start_date(3i) > unless Date::valid_date?(year.to_i, month.to_i, day.to_i) > errors.add(:start_date, "De startdatum moet een geldige datum > zijn.") > end > end > > But this doesn''t work, because I can''t access the values inside start_date > in the model. I get errors like that start_date is multiparameter . I know > that, but I can''t get to the values of the parameters. Hope somebody can > help.say you have a table like: create table moments ( id serial, moment timestamp ); and a controller like this: [ahoward@localhost date_validation]$ cat app/controllers/moment_controller.rb class MomentController < ApplicationController scaffold :moment end then a model like this will solve your problem [ahoward@localhost date_validation]$ cat app/models/moment.rb class ::Time class << self def normalized? t, values tvalues = %w(year month day hour min sec usec).map{|m| t.send m} values.zip(tvalues){|vin,vout| return true if vin != vout} return false end %w( local mktime gm utc ).each do |method| eval <<-code alias __org_#{ method }__ #{ method } def #{ method }(*a, &b) t = __org_#{ method }__(*a, &b) t.instance_eval{@original_arguments = a} t.instance_eval{@normalized = self.class.normalized? self, a} t end code end end attr_reader ''normalized'' alias_method ''normalized?'', ''normalized'' attr_reader ''original_arguments'' end class Moment < ActiveRecord::Base protected def validate *a, &b t = moment if t.nil? or t.normalized? values = t.original_arguments errors.add self.class.to_s, "bad time from <#{values.inspect}>" end super end end though you''d want to put the Time code somewhere else in practice... an attempt to enter Feb 31st on my system results in an error page that looks like <snip> Editing moment 1 error prohibited this moment from being saved There were problems with the following fields: * Moment bad time from <[2005, 2, 31, 11, 48]> i''ve posted this fix in the past but, for some reason, there was not much interest. read this thread for more info: http://wrath.rubyonrails.org/pipermail/rails/2005-March/004619.html this technique could easily be used to make a nice time/date validator and is, in fact, extensible for any multi-param rails object: the approach is always the same - try ctor, munge inputs if required, remember the original arguments for later access in validation. kind regards. -a -- ==============================================================================| ara [dot] t [dot] howard [at] noaa [dot] gov | all happiness comes from the desire for others to be happy. all misery | comes from the desire for oneself to be happy. | -- bodhicaryavatara ===============================================================================
--- Nick Snels <nick.snels-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi, > > I would like to validate a date (29 feb 2005 is > invalid) and if it is an > invalid date display an error to the user, using the > default way of > displaying errors. In my view I have a simple > date_select: > > <%= date_select (:listing, :start_date, > {:order => [:day, :month, :year], > :start_year => Time.now.year, > :end_year => Time.now.year+1}) %> > > When I save data to the db, the field start_date > should be validated and > if their is an error display it. So in my model I > have tried: > > def validate_on_create > year = start_date(1i) > month = start_date(2i) > day = start_date(3i) > unless Date::valid_date?(year.to_i, month.to_i, > day.to_i) > errors.add(:start_date, "De startdatum moet een > geldige datum > zijn.") > end > end > > But this doesn''t work, because I can''t access the > values inside > start_date in the model. I get errors like that > start_date is > multiparameter . I know that, but I can''t get to the > values of theI made a date validator: http://www.garbett.org/?q=node/27, as well as several other helpers. This code is free for the taking. No license just pure public domain. I relinquish all copyrights and all that other legal stuff on this code. May it help you. With this one can just put validates_date :birthdate in the model, and the problem is solved. Code from site: require ''parsedate'' ActiveRecord::Base.class_eval do def self.validate_date(string) data = ParseDate.parsedate(string) 0.upto(2) { |i| raise "Bogus date [#{string}] encountered" if data[i].nil? } raise "Pre-1800 date [#{string}] encountered" if data[0] < 1800 raise "Invalid date [#{string}] encountered" if nil==Date.new(data[0],data[1],data[2]) return true rescue Exception => e logger.error("Date format exception [#{e}]") return false end # Configuration options: # * message - A custom error message (default is: "can''t be blank") # * on - Specifies when this validation is active (default is :save, other options :create, :update) # * if - Specifies a method, proc or string to call to determine if the validation should # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The # method, proc or string should return or evaluate to a true or false value. def self.validates_date(*attr_names) configuration = { :message => ''Invalid date, use (MM/DD/YYYY)'', :on => :save } configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) attr_names.each do |attr_name| send(validation_method(configuration[:on])) do |record| unless configuration[:if] && !evaluate_condition(configuration[:if], record) date record.attributes_before_type_cast[attr_name.to_s] if not date.nil? and not date.class == Date and date.length > 0 and date.class == String and not self.validate_date(date) record.errors.add(attr_name,configuration[:message]) end end end end end end __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com
ara.t.howard-32lpuo7BZBA@public.gmane.org wrote:> On Sat, 3 Dec 2005, Nick Snels wrote: > >> I would like to validate a date (29 feb 2005 is invalid) and if it is an >> invalid date display an error to the user, using the default way of >> displaying errors. In my view I have a simple date_select:[snip]> say you have a table like: > > create table moments ( > id serial, > moment timestamp > ); > > and a controller like this: > > [ahoward@localhost date_validation]$ cat > app/controllers/moment_controller.rb > class MomentController < ApplicationController > scaffold :moment > end > > then a model like this will solve your problem[snip]> i''ve posted this fix in the past but, for some reason, there was not much > interest. read this thread for more info: > > http://wrath.rubyonrails.org/pipermail/rails/2005-March/004619.html > > this technique could easily be used to make a nice time/date validator > and is, > in fact, extensible for any multi-param rails object: the approach is > always > the same - try ctor, munge inputs if required, remember the original > arguments > for later access in validation. > > kind regards. > > -aHi, Ara - having discussed this with you over eight months ago, I would never have believed that Rails would reach 1.0 without sorting it out. Maybe date_select, like scaffolding, isn''t intended for production use. regards Justin
On Mon, 5 Dec 2005, Justin Forder wrote:> Hi, Ara - having discussed this with you over eight months ago, I would > never have believed that Rails would reach 1.0 without sorting it out. Maybe > date_select, like scaffolding, isn''t intended for production use.indeed. particularly when there are several viable alternatives that address the issue floating around. i''m not going to admit in public that i only remember i''d solved this once before until __after__ searching the archives and stubmling on the thread between you and i ;-) cheers. -a -- ==============================================================================| ara [dot] t [dot] howard [at] noaa [dot] gov | all happiness comes from the desire for others to be happy. all misery | comes from the desire for oneself to be happy. | -- bodhicaryavatara ===============================================================================