Недействительный срок службы Rails по модели приводит к нулю

У меня есть модель с атрибутом datetime. Я пытаюсь проверить входящий JSON, который будет обновлять модель. Но ActiveRecord, по-видимому, устанавливает значение атрибута в nil, если это недопустимое datetime. Я не могу ответить соответствующей ошибкой, потому что атрибуту разрешено быть nil. Что я делаю неправильно?

код:

class DatetimeValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    value.to_datetime rescue record.errors[attribute] << (options[:message] || "must be a date.")
  end
end

class Foo
   # column :my_date, :datetime
   validates :my_date, :allow_nil => true, :datetime => true
end

Консоль:

1.9.3p125 :001 > x = Foo.new
=> #<Foo id: nil, my_date: nil>
1.9.3p125 :001 > x.my_date = 'bad value'
=> 'bad value'
1.9.3p125 :001 > x.my_date
=> nil
1.9.3p125 :001 > x.valid?
=> true

Что касается ActiveRecord, установка атрибута datetime в "bad_value" эквивалентна установке его на нуль, поэтому я не могу его проверить, так как my_date не требуется. Мне это кажется ошибкой. Какое лучшее обходное решение?

Спасибо!

Ответы

Ответ 1

Одним из способов было бы переместить часть allow_nil в проверку date_time:

class DatetimeValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    return if value.blank?
    value.to_datetime rescue record.errors[attribute] << (options[:message] || "must be a date.")
  end
end

class Foo
  validates :my_date, :datetime => true
end

Изменить: я думаю, что это проблема с typecasting - попробуйте это (адаптировано из кода для validates :numericality):

def validate_each(record, attribute, value)
  before_type_cast = "#{attribute}_before_type_cast"

  raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast.to_sym)
  raw_value ||= value

  return if raw_value.blank?
  raw_value.to_datetime rescue record.errors[attribute] << (options[:message] || "must be a date.")
end