class ActiveModel::Validations::DateValidator

Date Validator. Inherits from ActiveModel::EachValidator.

Responds to the regular validator API methods `#check_validity` and `#validate_each`.

Constants

CHECKS

Implemented checks and their associated operators.

Public Class Methods

new(options) click to toggle source

Call `#initialize` on the superclass, adding a default `allow_nil: false` option.

Calls superclass method
# File lib/active_model/validations/date_validator.rb, line 25
def initialize(options)
  super(options.reverse_merge(allow_nil: false))
end

Public Instance Methods

check_validity!() click to toggle source

Validates the arguments passed to the validator.

They must be either any kind of Time, a Proc, or a Symbol.

# File lib/active_model/validations/date_validator.rb, line 32
def check_validity!
  keys = CHECKS.keys
  options.slice(*keys).each do |option, value|
    next if is_time?(value) || value.is_a?(Proc) || value.is_a?(Symbol) || (defined?(ActiveSupport::TimeWithZone) and value.is_a? ActiveSupport::TimeWithZone)
    raise ArgumentError, ":#{option} must be a time, a date, a time_with_zone, a symbol or a proc"
  end
end
validate(record) click to toggle source

Overridden because standard allow_nil and allow_blank checks don't work with string expressions that cannot be type cast to dates. We have to validate the pre-type cast values.

# File lib/active_model/validations/date_validator.rb, line 43
def validate(record)
  attributes.each do |attribute|
    value = record.read_attribute_for_validation(attribute)
    validate_each(record, attribute, value)
  end
end
validate_each(record, attr_name, value) click to toggle source

The actual validator method. It is called when ActiveRecord iterates over all the validators.

# File lib/active_model/validations/date_validator.rb, line 52
def validate_each(record, attr_name, value)
  before_type_cast = :"#{attr_name}_before_type_cast"

  value_before_type_cast = if record.respond_to?(before_type_cast)
    record.send(before_type_cast)
  else
    nil
  end

  if value_before_type_cast.present? && value.nil?
    record.errors.add(attr_name, :not_a_date, **options)
    return
  end

  return if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])

  unless value
    record.errors.add(attr_name, :not_a_date, **options)
    return
  end

  unless is_time?(value)
    record.errors.add(attr_name, :not_a_date, **options)
    return
  end

  options.slice(*CHECKS.keys).each do |option, option_value|
    option_value = option_value.call(record) if option_value.is_a?(Proc)
    option_value = record.send(option_value) if option_value.is_a?(Symbol)

    original_value = value
    original_option_value = option_value

    # To enable to_i conversion, these types must be converted to Datetimes
    if defined?(ActiveSupport::TimeWithZone)
      option_value = option_value.to_datetime if option_value.is_a?(ActiveSupport::TimeWithZone)
      value = value.to_datetime if value.is_a?(ActiveSupport::TimeWithZone)
    end

    if defined?(Date)
      option_value = option_value.to_datetime if option_value.is_a?(Date)
      value = value.to_datetime if value.is_a?(Date)
    end

    unless is_time?(option_value) && value.to_i.send(CHECKS[option], option_value.to_i)
      record.errors.add(attr_name, :"date_#{option}", **options.merge(
          value: original_value,
          date:  (I18n.localize(original_option_value) rescue original_option_value)
      ))
    end
  end
end

Private Instance Methods

is_time?(object) click to toggle source
# File lib/active_model/validations/date_validator.rb, line 107
def is_time?(object)
  object.is_a?(Time) || (defined?(Date) and object.is_a?(Date)) || (defined?(ActiveSupport::TimeWithZone) and object.is_a?(ActiveSupport::TimeWithZone))
end