avjaarsveld
avjaarsveld

Reputation: 599

Best date validation in Rails 4?

What is the best way to validate a date in Ruby on Rails? I need to make sure the "birthday" is a date, is less than 125 years ago and is not in the future (today is ok).

I have tried three methods:

1) date_validator gem

I used the following code (after installing the gem):

validates :birthday, 
date: {
  after: Proc.new {Time.now - 125.years}, message: :after,
  before: Proc.new {Time.now}, message: :cannot_be_in_the_future
  }

This worked except that I could set the date to the number 12 and pass validation.

2) Checking if the date is in a range of dates, in a custom validation method, like so:

from = 125.years.ago.to_date
to = Time.now.to_date
unless (from..to).include? birthday
  errors.add(:birthday, :custom_error_msg)
end

This worked well and passed all my tests, but the drawback is that you only get one error message. I would have liked separate error messages for the case when the date is in the future, when it is too long ago and when the input is not a date.

3) Multiple checks in a custom validation method, like so:

begin
  birthday.to_date
rescue
  errors.add(:birthday, "must be a date")
else
  if birthday > Time.now
    errors.add(:birtday, "cannot be in the future")
  elsif birthday < Time.now - 125.years
    errors.add(:birthday, "cannot be over 125 years ago")
  end
end

This also passes all my test, and I get different messages as explained above.

So I am wondering, is this the best method? Can it be improved at all (except that the error message text needs work)?

Thanks

Upvotes: 2

Views: 9066

Answers (3)

Victor Ch.
Victor Ch.

Reputation: 66

You can easily use validates_each method Just put there 2 validations:

1) For birthday in the past

    validates_each :birthday do |record, attr, value|
      record.errors.add(attr, 'must be in the past') if value >= Time.now.to_date
    end

2) For birthday not more than 150 years ago

    validates_each :birthday do |record, attr, value|
      record.errors.add(attr, 'must be less than 150 years in the past') 
                               if value <= (Time.now.to_date - 125.years) 
    end

Upvotes: 1

Ajay
Ajay

Reputation: 4251

For this simple validation, I think following ruby code is enough!
Please check :

validate :is_valid_dob?

  private
  def is_valid_dob?
    if((birthday.is_a?(Date) rescue ArgumentError) == ArgumentError)
      errors.add(:birthday, 'Sorry, Invalid Date of Birth Entered.')
    end
  end

Upvotes: 4

Alex Antonov
Alex Antonov

Reputation: 15146

Just use gem 'validates_timeliness'

In your case, using this gem

validates_date :birthday, on_or_after: lambda { 125.years.ago }

Upvotes: 1

Related Questions