4

I am using the timeliness gem to do time and date validation.

My event model has a time field storing a string like "11:15", a start_date and end_date storing a Date object.

I want the following validation behaviour:

If a user tries to create an event on the current day of the year (so start_date == Date.today), and the time is in the past (so if it was 15:30 when the event was created and the user entered 11:30), then the validation should fail. I.e we only want events created where the date is today or is in the future, and the time, if the date is today, is in the future.

I am trying the following validation for this:

validates :time, :presence => true,
    :timeliness => { :type => :time, :on_or_after => lambda { if(:start_date == Date.today && :day_of_week.downcase == Date.today.strftime("%A").downcase) then return Time.new(:time.to_s).in_time_zone(:timezone)>Time.now.in_time_zone(:timezone) else return true end } }

However it is not behaving correctly. I.e I am able to create an event with the start_date of 03/08/2015 and a time of 09:00 despite it being 15:31 on 03/08/2015! Please help!

1
  • 1
    To my mind you have a big lambda expression and it's better to define a method instead of lambda. It's hard to read for me. This will become validates :time, :presence => true, :timeliness => correct_time. Commented Aug 3, 2015 at 14:37

1 Answer 1

1

Your lambda doesn't make a lot of sense, because you're using symbols everywhere - :start_date == Date.today will always be false. The value of lambdas in validations is that they're passed your Event instance, so you can reference event.start_date. I agree with @arthur.karganyan in the comments that if you need something this complicated, it'll be easier to work with as a method.

But, you're also making this much more complicated than you need to. It looks like you have start_date and time as separate attributes, which is difficult to work with because they'll tend to rely on each other. I'd recommend making those a single start_time attribute instead, and then you can use validates_timeliness like so:

validates_datetime :start_time, on_or_after: -> { Time.now }

If you must have separate attributes, your validations might look like:

validates_date :start_date, on_or_after: -> { Date.today }
validates_time :time, on_or_after: lambda { |event| Time.now if event.start_date.today? }

This validates that the date is today or in the future, and if it's today, also checks the time. validates_timeliness appears to accept any time when on_or_after lambda evaluates to nil.

Sign up to request clarification or add additional context in comments.

6 Comments

I have tried : validates :time, :presence => true, :timeliness => { :type => :time, :on_or_after => { Time.now if start_date.today? } } however this resulted in a syntax - so i added lambda before the block, which fixed the error but the validation still fails to catch times less than the current time
Pay attention to your syntax. Your :on_or_after => { Time.now... } is trying to set a block as a hash value. Note the difference between => (hash rocket) and -> (lambda literal)
Even doing exactly as you have it fails to trigger a validation error?
As in if I try : validates_time :time, on_or_after: -> { Time.now if start_date.today? } and I do a time of "11:30" and a start_date of Today it does not fail validation.
@RenegadeAndy My apologies, I was referencing things on self when in fact the validation lambdas receive the instance as an argument. Updated the answer with code I've actually run :)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.