From 9a8a82c6992451c021e564a989ae82a3e6c193c4 Mon Sep 17 00:00:00 2001 From: Adam Meehan Date: Sat, 3 May 2008 18:12:51 +1000 Subject: [PATCH] fixed restriction value conversion and added nil check --- lib/validates_timeliness/validations.rb | 65 +++++++++++++++---------- spec/attribute_methods_spec.rb | 2 +- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/lib/validates_timeliness/validations.rb b/lib/validates_timeliness/validations.rb index 60b2bfc..09c7b03 100644 --- a/lib/validates_timeliness/validations.rb +++ b/lib/validates_timeliness/validations.rb @@ -8,48 +8,56 @@ module ValidatesTimeliness module ClassMethods def validates_timeliness_of(*attr_names) - # possible options only_date only_time only_epoch - configuration = { :on => :save, :allow_nil => false } + configuration = { :on => :save, :allow_nil => false, :allow_blank => false } configuration.update(attr_names.extract_options!) restriction_methods = {:before => '<', :after => '>', :on_or_before => '<=', :on_or_after => '>='} - - validates_each(attr_names, configuration) do |record, attr_name, value| - raw_value = record.send("#{attr_name}_before_type_cast") || value - - if raw_value.nil? - record.errors.add(attr_name, "cant' be blank") unless configuration[:allow_nil] - next - end + + # we need to check raw value for blank or nil to catch when invalid value returns nil + allow_nil = configuration.delete(:allow_nil) + allow_blank = configuration.delete(:allow_blank) + + validates_each(attr_names, configuration) do |record, attr_name, value| + raw_value = record.send("#{attr_name}_before_type_cast") + + next if (raw_value.nil? && allow_nil) || (raw_value.blank? && allow_blank) + + record.errors.add(attr_name, "can't be blank") and next if raw_value.blank? column = record.column_for_attribute(attr_name) begin - time = if raw_value.acts_like?(:time) + time = if raw_value.acts_like?(:time) || raw_value.is_a?(Date) raw_value - elsif raw_value.is_a?(Date) - raw_value.to_time else time_array = ParseDate.parsedate(raw_value) - # checks if date is valid and enforces number of days in a month unlike Time - date = Date.new(*time_array[0..2]) + # checks if date is valid which enforces number of days in a month unlike Time + Date.new(*time_array[0..2]) - # checks if time is valid as it will accept bad date values + # checks if time is valid and return object Time.mktime(*time_array) end + conversion_method = column.type == :date ? :to_date : :to_time + time = time.send(conversion_method) + restriction_methods.each do |option, method| if restriction = configuration[option] - compare = case restriction - when Time, Date, DateTime - restriction.to_time - when Symbol - record.send(restriction).to_time - when Proc - restriction.call(record) - end - - begin + begin + compare = case restriction + when Date + restriction + when Time, DateTime + restriction.respond_to?(:in_time_zone) ? restriction.in_time_zone : restriction + when Symbol + record.send(restriction) + when Proc + restriction.call(record) + end + + next if compare.nil? + compare = compare.send(conversion_method) if compare + record.errors.add(attr_name, "must be #{option.to_s.humanize.downcase} #{compare}") unless time.send(method, compare) rescue record.errors.add(attr_name, "restriction '#{option}' value was invalid") @@ -63,8 +71,11 @@ module ValidatesTimeliness end end - end + end + alias validates_times validates_timeliness_of + alias validates_dates validates_timeliness_of + alias validates_datetimes validates_timeliness_of end end diff --git a/spec/attribute_methods_spec.rb b/spec/attribute_methods_spec.rb index 796ee34..8226e0b 100644 --- a/spec/attribute_methods_spec.rb +++ b/spec/attribute_methods_spec.rb @@ -9,7 +9,7 @@ describe ValidatesTimeliness::AttributeMethods do it "should return string value for attribute_before_type_cast when written as string" do @person.birth_date_and_time = "1980-12-25 01:02:03" - @person.birth_date_and_time_before_type_cast.should == "1980-12-25 01:02:03" + @person.birth_date_and_time_before_type_cast.should == "1980-12-25 01:02:03" end it "should return Time object for attribute_before_type_cast when written as Time" do