2010-11-19 50 views
6

我有一个Rails 3应用程序(使用Mongodb和Mongoid,如果这有所作为),并且在我的一个模型中,我有一个字段定义为日期类型。在Rails 3中的日期验证

class Participant 
    include Mongoid::Document 

    field :birth_date, :type => Date 
end 

我的控制器是采用蒙戈的find_or_initialize_by特点:

class ParticipantController 

    def create 
    @participant = Participant.find_or_initialize_by(params[:participant]) 
    if @participant.save 
     redirect_to participants_path 
    else 
     render :new 
    end 
    end 
end 

这一切都归结为:我该怎么办日期验证加载ActiveModel中与Mongoid和Rails 3?

我想确保在文本框中输入“blah”在分配给我的模型的.birth_date字段时不会引发异常。它应该提供一个很好的验证错误消息,而不使用控制器来进行验证。

这里的基本要求:

  • 的观点必须是单个文本框。 没有别的。这是一个用户 要求,我们不能改变

  • 验证应在 模型来完成,而不是在控制器或
    视图(JavaScript或其他)

  • 没有正则表达式格式验证(他们不工作的权利/支持的语言环境等)

的问题是,从文本框中的值是validates_format_of之前分配给.birth_date和validates_presence_of中运行。所以...

我该如何截取值的赋值,以便在赋值之前验证它?是否有可能在模型中使用ActiveModel?或者这是否需要我将代码放入控制器才能执行此操作?

+0

你怎么没有在你的控制器中进行日期验证?在你的模型中定义一个方法,如果日期无效,然后让你的控制器使用像“raise”这样的方法,则引发一个'ArgumentError'你没有指定一个有效的日期“除非@ participant.date_is_valid' – Alex 2010-11-19 02:49:03

+0

另外,你能提供一个有关“有效”日期的含义的更多细节?一个有效的RFC标准日期时间字符串?日期可以用许多不同的方式进行格式化。任何更多的信息将是有帮助的 – Alex 2010-11-19 03:02:12

回答

8

这个代码小块可以做的伎俩

retVal = "it is a date" 
begin 
    y = Date.parse("rodman was here") 
rescue 
    retVal = "nope not a date" 
end 

puts retVal 
+2

尽可能多的,因为我不喜欢它,这是我们最终使用。其中一天,我打算写一个rails插件来处理这个更优雅的问题....这些日子之一......当我有空闲的时候...:P – 2011-01-18 14:06:15

+2

我推荐validates_timeliness gem。 – 2012-08-06 18:51:39

2

我刚刚发现这一点,虽然我还没有发挥它:

http://blog.codegram.com/2011/2/date-validation-with-rails-3

Github上库是在https://github.com/codegram/date_validator

从博文中引用:

“你可以用它无论是在Rails 3个的模型或任何自定义类(需要加载ActiveModel后),在一个非常简单的方式

他们也给这使得它看起来像它应该工作的范例你 - 它是在模型中完成的,而不是在控制器中完成的。

validates expiration_date, 
    :date => { :after => Time.now, :before => Time.now + 1.year } 
+3

在类上下文中非常小心时间戳。在Rails生产中,这些日期将是该类定义的时间,即应用程序服务器启动的时间。正如date_validator文档中提到的那样,在'Proc'中传递日期。 – 2012-02-27 16:04:57

2

您需要使用before_validation过滤器来处理例如 模型中的

class Participant 
    include Mongoid::Document 
    before_validation :make_a_date 
    field :birth_date, :type => Date 

    private 
    def make_a_date 
    #do all sorts of manipulation of the date here 
    end 
end 

另一种选择是创建自己的验证方法是什么?但我不认为这就是你想要的...

0

另一种方法是创建一个扩展::加载ActiveModel一个EachValidator验证类,如:

class TimeValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    if value && !value.kind_of?(Time) 
     record.errors[attribute] << (options[:message] || "don't recognise time") 
    end 
    end 
end 

在我这个连接上面的例子在模型中使用setter方法处理解析,如果传递字符串。我想支持模糊日期时间匹配,所以我使用的是Chronic

require 'chronic' 

def starts_at=(value) 
    if value.kind_of?(String) && parsed_time = Chronic.parse(value) 
    @starts_at = parsed_time.utc 
    else 
    @starts_at = value 
    end 
end 

,这建立验证的模型

validates :starts_at, :time => true 

这是很好的和传统。

+0

但是如果日期来自用户输入'kind_of?(Time)'将始终返回false。 '“12/12/1912”.kind_of?(Date)=> false'。那么这将如何工作? – Mohamad 2013-04-25 18:36:29

4

validates_timeliness宝石很漂亮。你可以这样做:

class Participant < ActiveRecord::Base 
    validates_date :birth_date 
end