Ruby-on-rails 如何验证 Rails 中的日期?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/597328/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:00:41  来源:igfitidea点击:

How do I validate a date in rails?

ruby-on-railsrubyvalidationdate

提问by Megamug

I want to validate a date in my model in Ruby on Rails, however, the day, month and year values are already converted into an incorrect date by the time they reach my model.

我想在 Ruby on Rails 中验证我模型中的日期,但是,当它们到达我的模型时,日、月和年值已经转换为不正确的日期。

For example, if I enter February 31st 2009 in my view, when I use Model.new(params[:model])in my controller, it converts it to "March 3rd 2009", which my model then sees as a valid date, which it is, but it is incorrect.

例如,如果我在视图中输入 2009 年 2 月 31 日,当我Model.new(params[:model])在控制器中使用时,它会将其转换为“2009 年 3 月 3 日”,然后我的模型将其视为有效日期,确实如此,但它是不正确的。

I would like to be able to do this validation in my model. Is there any way that I can, or am I going about this completely wrong?

我希望能够在我的模型中进行此验证。有什么办法可以,还是我完全错误?

I found this "Date validation" that discusses the problem but it never was resolved.

我发现这个“日期验证”讨论了这个问题,但它从未得到解决。

采纳答案by Hyman Chu

I'm guessing you're using the date_selecthelper 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):

我猜你正在使用date_select助手来生成日期标签。另一种方法是对日、月、年字段使用选择表单助手。像这样(我使用的例子是 created_at 日期字段):

<%= 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_timelinessplugin. It works like this (from the github page):

如果您正在寻找插件解决方案,我会查看validates_timeliness插件。它的工作原理是这样的(来自 github 页面):

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.

回答by Roger

Using the chronic gem:

使用慢性宝石:

class MyModel < ActiveRecord::Base
  validate :valid_date?

  def valid_date?
    unless Chronic.parse(from_date)
      errors.add(:from_date, "is missing or invalid")
    end
  end

end

回答by Txus

If you want Rails 3 or Ruby 1.9 compatibility try the date_validatorgem.

如果您希望与 Rails 3 或 Ruby 1.9 兼容,请尝试使用date_validatorgem。

回答by joshuacronemeyer

Active Record gives you _before_type_castattributes which contain the raw attribute data before typecasting. This can be useful for returning error messages with pre-typecast values or just doing validations that aren't possible after typecast.

Active Record_before_type_cast在类型转换之前为您提供包含原始属性数据的属性。这对于返回带有预类型转换值的错误消息或仅进行类型转换后无法进行的验证非常有用。

I would shy away from Daniel Von Fange's suggestion of overriding the accessor, because doing validation in an accessor changes the accessor contract slightly. Active Record has a feature explicitly for this situation. Use it.

我会回避 Daniel Von Fange 的覆盖访问器的建议,因为在访问器中进行验证会稍微改变访问器契约。Active Record 具有针对这种情况的明确功能。用它。

回答by Daniel Von Fange

Since you need to handle the date string before it is converted to a date in your model, I'd override the accessor for that field

由于您需要在将日期字符串转换为模型中的日期之前对其进行处理,因此我将覆盖该字段的访问器

Let's say your date field is published_date. Add this to your model object:

假设您的日期字段是published_date. 将此添加到您的模型对象中:

def published_date=(value)
    # do sanity checking here
    # then hand it back to rails to convert and store
    self.write_attribute(:published_date, value) 
end

回答by unmultimedio

A bit late here, but thanks to "How do I validate a date in rails?" I managed to write this validator, hope is useful to somebody:

这里有点晚了,但感谢“我如何在 rails 中验证日期?”我设法编写了这个验证器,希望对某人有用:

Inside your model.rb

在你的里面 model.rb

validate :date_field_must_be_a_date_or_blank

# If your field is called :date_field, use :date_field_before_type_cast
def date_field_must_be_a_date_or_blank
  date_field_before_type_cast.to_date
rescue ArgumentError
  errors.add(:birthday, :invalid)
end

回答by Trip

Here's a non-chronic answer..

这是一个非慢性答案..

class Pimping < ActiveRecord::Base

validate :valid_date?

def valid_date?
  if scheduled_on.present?
    unless scheduled_on.is_a?(Time)
      errors.add(:scheduled_on, "Is an invalid date.")
    end
  end
end

回答by King'ori Maina

You can validate the date and time like so (in a method somewhere in your controller with access to your params if you are using custom selects) ...

您可以像这样验证日期和时间(如果您使用自定义选择,则可以在控制器中某处的方法中访问您的参数)...

# Set parameters
year = params[:date][:year].to_i
month = params[:date][:month].to_i
mday = params[:date][:mday].to_i
hour = params[:date][:hour].to_i
minute = params[:date][:minute].to_i

# Validate date, time and hour
valid_date    = Date.valid_date? year, month, mday
valid_hour    = (0..23).to_a.include? hour
valid_minute  = (0..59).to_a.include? minute
valid_time    = valid_hour && valid_minute

# Check if parameters are valid and generate appropriate date
if valid_date && valid_time
  second = 0
  offset = '0'
  DateTime.civil(year, month, mday, hour, minute, second, offset)
else
  # Some fallback if you want like ...
  DateTime.current.utc
end

回答by Ryan Duffield

Have you tried the validates_date_timeplug-in?

你试过validates_date_time插件吗?