Ruby on rails Rails:在类型转换之前验证模型中的日期

Ruby on rails Rails:在类型转换之前验证模型中的日期,ruby-on-rails,validation,date,Ruby On Rails,Validation,Date,当在表单中输入格式错误或无效的日期(例如非闰年的2月29日)时,任何验证都会访问一个nil值。原因是Rails中的验证是在将原始字符串类型转换为日期变量后进行的:如果失败(出于上述原因),类型转换将返回一个nil值,该值存储在模型的属性中 我发现我可以通过属性\u-before\u-type\u-cast函数访问原始日期字符串,因此能够编写以下自定义验证器: class DateFieldValidator < ActiveModel::EachValidator def valid

当在表单中输入格式错误或无效的日期(例如非闰年的2月29日)时,任何验证都会访问一个nil值。原因是Rails中的验证是在将原始字符串类型转换为日期变量后进行的:如果失败(出于上述原因),类型转换将返回一个nil值,该值存储在模型的属性中

我发现我可以通过
属性\u-before\u-type\u-cast
函数访问原始日期字符串,因此能够编写以下自定义验证器:

class DateFieldValidator < ActiveModel::EachValidator

  def validate_each( record, attribute, value )

    # this may be interesting only if value could not be read

    return unless value.nil?

    # but not if original value was blank

    original_value = record.read_attribute_before_type_cast( attribute )
        return if original_value.blank?

    # ignore any other value but String

    return unless original_value.is_a? String

    # _parse must return some useful values

    parsed_value = Date._parse( original_value )
    unless [ :year, :mon, :mday ].all? { |key| parsed_value.has_key?( key ) }
      record.errors.add( attribute, ( options[ :message ] || I18n.t( 'validators.date_field.bad_syntax' )))
      return
    end

    # valid_date? must return true

    unless Date.valid_date?( parsed_value[ :year ], parsed_value[ :mon ], parsed_value[ :mday ])
      record.errors.add( attribute, ( options[ :message ] || I18n.t( 'validators.date_field.bad_date' )))
      return
    end

  # date is OK

  end
end
类DateFieldValidator 这很好,但是如果日期是必需的(validate is with presence:true),我会收到两个验证错误,一个来自我的验证器,另一个来自Rails,告诉用户缺少必需的属性

这可能会激怒用户,尤其是因为表单上(当前)没有显示原始的坏值。我是否应该在表单中显示原始值并删除Rails生成的错误消息


P.S.一个日期选择器只用于插入有效日期不是一个选项,因为我必须考虑到未来的日期,这将需要在日期选择器中大量点击。

不要使用Rails验证,就你的属性而言。@japed:那将是下一个问题:有没有办法使代码干涸,这样我就可以对所需和可选的日期使用相同的验证器……记录:我刚刚找到了上面问题的解决方案!选项散列可以用我自己的参数(和值)填充,例如“presence:true”。用“if options[:presence]&&value.blank?record.errors.add(attribute,:blank)”展开上面的解决方案,允许我使用validates:attribute,date_字段:{presence:true/false}。