【问题标题】:Date Validation In Rails 3Rails 3 中的日期验证
【发布时间】:2010-11-19 02:21:01
【问题描述】:

我有一个 Rails 3 应用程序(使用 Mongodb 和 Mongoid 如果有区别的话),在我的一个模型中,我有一个定义为 Date 类型的字段。

class Participant
  include Mongoid::Document

  field :birth_date, :type => Date
end

我的控制器正在使用 mongo 的 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 和 validates_presence_of 之前,文本框中的值已分配给 .birth_date。所以……

如何截取值的赋值,以便在赋值之前对其进行验证?是否可以在模型中使用 ActiveModel 做到这一点?或者这是否需要我在控制器中添加代码才能做到这一点?

【问题讨论】:

  • 您为什么不在控制器中进行日期验证?在您的模型中定义一个方法,如果日期无效,则引发ArgumentError,然后让您的控制器使用该方法,如raise "You did not specify a valid date" unless @participant.date_is_valid
  • 另外,您能否提供更多关于valid 日期的意思的详细信息?有效的 RFC 标准日期时间字符串?日期可以用许多不同的方式格式化。任何更多信息都会有所帮助

标签: validation date ruby-on-rails-3 mongodb


【解决方案1】:

这个小代码块可以解决问题

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

puts retVal

【讨论】:

  • 尽管我不喜欢它,但这就是我们最终使用的。在这些日子里,我将编写一个 Rails 插件来更优雅地处理这个问题......这些日子里......当我有空闲时间时......:P
  • 我推荐 validates_timeliness gem。
【解决方案2】:

validates_timeliness gem 非常可爱。你可以这样做:

class Participant < ActiveRecord::Base
  validates_date :birth_date
end

【讨论】:

    【解决方案3】:

    我刚刚发现了这个,虽然我还没有玩过它:

    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 }
    

    【讨论】:

    • 要非常小心类上下文中的时间戳。在 Rails 生产环境中,这些日期将是定义类的时间,也就是启动应用服务器的时间。正如 date_validator 文档所提到的,在 Proc 中传递日期。
    【解决方案4】:

    您需要使用 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
    

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

    【讨论】:

      【解决方案5】:

      另一种方法是创建一个扩展 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
      

      既好又传统。

      【讨论】:

      • 但如果日期来自用户输入 kind_of?(Time) 将始终返回 false。 "12/12/1912".kind_of?(Date) =&gt; false。那么这将如何运作呢?
      猜你喜欢
      • 2011-08-05
      • 1970-01-01
      • 1970-01-01
      • 2015-03-12
      • 2010-11-22
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      • 2011-09-22
      相关资源
      最近更新 更多