I have an Active Record model that contains attributes: expiry_date. How do I go about validating it such that it is after today(present date at that time)? I am totally new to
In rails 4+ there are future?
and past?
methods for DateTime
objects, so a simpler answer is
class Invoice < ActiveRecord::Base
validate :expiration_date_cannot_be_in_the_past
def expiration_date_cannot_be_in_the_past
if expiration_date.present? && expiration_date.past?
errors.add(:expiration_date, "can't be in the past")
end
end
end
I took @dankohn answer, and updated to be I18n ready. I also removed the blank
test, because that's not the responsibility of this validator, and can easily be enabled by adding presence: true
to the validates call.
The updated class, now named in_future
, which I think is nicer than not_in_past
class InFutureValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors.add(attribute, (options[:message] || :in_future)) unless in_future?(value)
end
def in_future?(date)
date.present? && date > Time.zone.today
end
end
Now add the in_future
key to your localization file.
For all fields under errors.messages.in_future
, e.g. for Dutch:
nl:
errors:
messages:
in_future: 'moet in de toekomst zijn'
Or per field under activerecord.errors.models.MODEL.attributes.FIELD.in_future
, e.g. for the end_date
in a Vacancy
model in Dutch:
nl:
activerecord:
errors:
models:
vacancy:
attributes:
end_date:
in_future: 'moet in de toekomst zijn'
Here's the code to set up a custom validator:
#app/validators/not_in_past_validator.rb
class NotInPastValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if value.blank?
record.errors.add attribute, (options[:message] || "can't be blank")
elsif value <= Time.zone.today
record.errors.add attribute,
(options[:message] || "can't be in the past")
end
end
end
And in your model:
validates :signed_date, not_in_past: true
Your question is (almost) exactly answered in the Rails guides.
Here's the example code they give. This class validates that the date is in the past, while your question is how to validate that the date is in the future, but adapting it should be pretty easy:
class Invoice < ActiveRecord::Base
validate :expiration_date_cannot_be_in_the_past
def expiration_date_cannot_be_in_the_past
if expiration_date.present? && expiration_date < Date.today
errors.add(:expiration_date, "can't be in the past")
end
end
end
The simplest and working solution is to use the in-built validation from Rails. Just validates it like that:
validates :expiry_date, inclusion: { in: (Date.today..Date.today+5.years) }