如果在表单中输入格式不正确或无效的日期(例如,非闰年的2月29日),则任何验证似乎都会访问零值。这样做的原因是Rails中的验证发生在将原始字符串转换为日期变量后:如果失败(由于上述原因),类型转换返回一个nil值,该值存储在模型的属性中。
我发现我可以通过attribute_before_type_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
这很好但是如果日期是必需的(validate is with presence:true)我得到两个验证错误,一个来自我的验证器,另一个来自Rails,告诉用户缺少必需的属性。
这可能会刺激用户,特别是因为原始的错误值(当前)没有显示在表单上。我应该在表单中显示原始值并删除Rails生成的错误消息吗?
P.S。作为帮助者的日期选择器只能插入有效日期,因此我不得不考虑将来需要大量点击日期选择器的日期。