RenegadeAndy
RenegadeAndy

Reputation: 5690

A lambda expression in a rails validation statement

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!

Upvotes: 4

Views: 8379

Answers (1)

Kristján
Kristján

Reputation: 18813

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.

Upvotes: 1

Related Questions