How to Validate a Date in Rails

How do I validate a date in rails?

I'm guessing you're using the date_select helper to generate the tags for the date. Another way you could do it is to use select form helper for the day, month, year fields. Like this (example I used is the created_at date field):

<%= f.select :month, (1..12).to_a, selected: @user.created_at.month %>
<%= f.select :day, (1..31).to_a, selected: @user.created_at.day %>
<%= f.select :year, ((Time.now.year - 20)..Time.now.year).to_a, selected: @user.created_at.year %>

And in the model, you validate the date:

attr_accessor :month, :day, :year
validate :validate_created_at

private

def convert_created_at
begin
self.created_at = Date.civil(self.year.to_i, self.month.to_i, self.day.to_i)
rescue ArgumentError
false
end
end

def validate_created_at
errors.add("Created at date", "is invalid.") unless convert_created_at
end

If you're looking for a plugin solution, I'd checkout the validates_timeliness plugin. It works like this (from the github page):

class Person < ActiveRecord::Base
validates_date :date_of_birth, on_or_before: lambda { Date.current }
# or
validates :date_of_birth, timeliness: { on_or_before: lambda { Date.current }, type: :date }
end

The list of validation methods available are as follows:

validates_date     - validate value as date
validates_time - validate value as time only i.e. '12:20pm'
validates_datetime - validate value as a full date and time
validates - use the :timeliness key and set the type in the hash.

Rails validate type date?

Rails doesn't support this directly; the closest it comes is probably validates_format_of, or supplying your own custom validator.

I think what you want is the validates_timeliness gem. It not only validates that something is a valid date, but you can specify whether it should be before or after today and various other date range checks.

Validation between two date rails

You're going to have to have a separate method to hold the complex validation code. Use validate :method_name (without an 's') to call it.

The method should add error(s) to the object if it finds a problem.

Something like this:

validate :no_reservation_overlap

scope :overlapping, ->(period_start, period_end) do
where "((date_start <= ?) and (date_end >= ?))", period_end, period_start
end


private

def no_reservation_overlap
if (Reservation.overlapping(date_start, date_end).any?)
errors.add(:date_end, 'it overlaps another reservation')
end
end

Rails date of birth confirmation validation

I ended up changing the controller logic to instead put the logic of formatting the date_of_birth_confirmation in the model which is probably where it better fits.

   # User.rb
before_validation :format_date_of_birth_confirmation

def format_date_of_birth_confirmation
return if date_of_birth_confirmation.blank?
return if date_of_birth_confirmation.is_a?(Date)

year = date_of_birth_confirmation[1]
month = date_of_birth_confirmation[2]
day = date_of_birth_confirmation[3]

return unless year && month && day

assign_attributes(date_of_birth_confirmation: "#{year}-#{month}-#{day}".to_date)
end

Validating date formats in rails

I've not tested your code within a Rails app, but your regular expression looks good to me. Try this test program:

#!/usr/bin/ruby

str = '08/24/2009'
regex = /\d{2}\/\d{2}\/\d{4}/

if str =~ regex
print 'matched', "\n"
else
print 'did not match', "\n"
end

Your regular expression matches. That suggests the problem is elsewhere.

You also might think about trying more general solutions for parsing a date in Ruby, such as the Date.parse method of the Date class. This does a little bit more validation than your regular expression, and it also provides some useful methods for converting dates between different formats.

Rails date validation with conditional validation if and future? method

Thank you for Mark Merritt because I inspired his answer.

Actually the answer works perfect, but the problem is keeping the model DRY, and also, it has long method name.

Here is what I've done. Pull request, and the commit

I created separate validator which is name at_future_validator.rb. I placed the file inside of lib/validators folder.

Then, I wrote this validator

# lib/validators/at_future_validator.rb
class AtFutureValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
if attribute.present? && value < Date.today
object.errors[attribute] << (options[:message] || 'must be in the future')
end
end
end

OK. The first part has done. The important part is, which I saw now on the guide, working with custom validator which we named at_future_validator. We need to require the validator inside of the house model.

# app/models/house.rb
class House < ApplicationRecord
require_dependency 'validators/at_future_validator.rb'
# ...
validates :available_at, presence: true, at_future: true
# ...
end

Guides that I followed

#211 Validations in Rails 3 - 8:09

Validate graduation date in Rails 5 model

 validates :grad_year, numericality: { greater_than_or_equal_to: Date.today.year, less_than_or_equal_to: Date.today.year + 5 }, allow_nil: true

How to validate the date such that it is after today in Rails?

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

How to validate (and handle) if value passed to .to_date is valid or returns error?

It could be achieved with rescue, and then addes to errors

class Post < ActiveRecord::Base

validate do |post|
begin
Date.parse(post.date)
rescue ArgumentError
errors.add(:date, "must be a valid date")
end
end

## Another way

validate do |post|
# make sure that `date` field in your database is type of `date`
errors.add(:date, "must be a valid date") unless post.date.try(to_date)
end
end


Related Topics



Leave a reply



Submit