EDIT: In case the question below looks a bit 'extensive', the summary is that I just want to combine a date field and an optional time field in my model purely for the purpose of validating it using a date validator but I can't get my test to fail correctly when I pass in a string as the time.
EDIT 2: Since I'm still struggling to find a way to join a date object with a time object for the purpose of validation then I wondered if I could just validate that the time value was a Time object using is_a?(Time)
(rather than an invalid string) but that didn't seem to work either and I wondered if it was because of the Time
mention with this method (but I don't quite understand it enough to know whether that causes an issue or not.
I also wondered whether the to_time
method could help me check whether something is a Time object but I'm not sure how.
Hopefully someone can either advise on how to join a Date
object with a Time
object for the purpose of validation or at least tell me how I can check that the time value being submitted is a Time
object and not an invalid string or something.
EDIT 3: I've just tried the following based on another answer I found but it still doesn't complain about the "invalid" string in the test:
validate :start_time_is_time?, :if => "start_time.present?"
def start_time_is_time?
unless start_time.is_a?(Time) || ((Time.parse(start_time) rescue ArgumentError) == ArgumentError)
errors.add(:start_time, 'must be a valid time')
end
end
Is there any reason why the string may be considered as a valid Time
?
I have a view similar to Trying to set a variable in before_validation but it isn't working with a view that uses a calendar to select a day and drop downs to select time. I tried to apply the same to my model but couldn't get it to work since I'm a little new to ruby and was having trouble filling in the blanks left by the answer.
My model has start_date and start_time fields.
I need to combine these 2 fields just so that I can validate them together as a datetime (using the date_validator gem) rather than having to validate the date and time separately, although they will go into the database as separate fields, unless someone can persuade me otherwise (although I've done a lot with them separately so don't really want to change this).
A date has to be submitted but the time field is optional.
From the other question it looks like I need a before_validation method that can combine the 2 fields as required into a virtual field that I can then validate using the date_validator gem.
EDIT: original error has been corrected thanks to RyanJM but I still can't get the test to pass correctly. Below is the current state of play.
Here's the basics of my Showtime model now:
class Showtime < ActiveRecord::Base
attr_accessible :start_date, :start_time
attr_accessor :starting_at, :starting_time
belongs_to :performance
before_validation :construct_starting_at
validates :start_date, :presence => true, :date => { :after_or_equal_to => Proc.new { Date.today } }
validates :starting_at, :date => { :after_or_equal_to => Proc.new { Time.now } }, :if => "start_date.present? && start_time.present?"
def construct_starting_at
if start_date.present? && start_time.present?
self.starting_time = self.start_time.strftime("%T")
self.starting_at = DateTime.strptime("#{start_date} #{starting_time}", "%F %T")
end
end
end
In case it is required, here's the basics/relevant parts of the Performance model:
class Performance < ActiveRecord::Base
has_many :showtimes, :dependent => :delete_all
accepts_nested_attributes_for :showtimes, :allow_destroy => true, :reject_if => lambda { |a| a[:start_date].blank? }
end
Here's the failing test:
require 'spec_helper'
describe Showtime do
before(:each) do
@attr = {
:name => "Performance 1",
:showtimes_attributes => {
"0" => {
:start_date => Date.today+15.days,
:start_time => Time.now
}
}
}
end
it "should test that the start time is a valid time if it exists" do
@attr_invalid = {
"0" => {
:start_date => Date.today+15.days,
:start_time => "invalid"
}
}
invalid = Performance.create(@attr.merge(:showtimes_attributes => @attr_invalid))
invalid.should_not be_valid
end
end
Hopefully I've not broken anything in the above code in my attempt to just show the necessary parts.
I'm haven't used the date_validator gem, but validates_timeliness does this sort of thing pretty well and also seems to be more actively maintained.
Here's what finally pointed me in the right direction: https://github.com/codegram/date_validator/issues/25#issuecomment-6126879
来源:https://stackoverflow.com/questions/9955977/validate-date-and-time-fields-together-in-rails-model