【问题标题】:Validating a Model Property is Greater than Another验证模型属性大于另一个
【发布时间】:2009-12-22 13:03:35
【问题描述】:

首先,让我说我是非常 Rails 的新手(玩过一两次,但现在强迫自己用它写一个完整的项目,昨天就开始了)。

我现在正在尝试验证模型属性(术语?)是否大于另一个。这似乎是带有greater_than 选项的validates_numericality_of 的完美实例,但可惜这会引发错误,告诉我greater_than expects a number, not a symbol。如果我尝试对该符号进行类型转换 .to_f 我会收到 undefined method 错误。

这是我最终所做的,我很好奇是否有更好的方法。这只是一个控制项目发布的简单系统,我们只有主要/次要版本(单点),所以浮动在这里感觉是正确的决定。

class Project < ActiveRecord::Base
    validates_numericality_of :current_release
    validates_numericality_of :next_release
    validate :next_release_is_greater

    def next_release_is_greater
        errors.add_to_base("Next release must be greater than current release") unless next_release.to_f > current_release.to_f
    end
end

这行得通 - 它通过了相关的单元测试(以下是为了您的观看乐趣),我只是想知道是否有更简单的方法 - 我本可以尝试其他方法。

相关单元测试:

# Fixture data:
#   PALS:
#     name: PALS
#     description: This is the PALS project
#     current_release: 1.0
#     next_release: 2.0
#     project_category: 1
#     user: 1
def test_release_is_future
    project = Project.first(:conditions => {:name => 'PALS'})
    project.current_release = 10.0
    assert !project.save

    project.current_release = 1.0
    assert project.save
end

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    如您所见,唯一的方法是使用自定义验证器。 :greater_than 选项应该是一个整数。以下代码不起作用,因为当前版本和下一个版本都仅在实例级别可用。

    class Project < ActiveRecord::Base
      validates_numericality_of :current_release
      validates_numericality_of :next_release, :greater_than => :current_release
    end
    

    greater_than 选项的目的是根据静态常量或其他类方法验证值。

    所以,不要介意,继续使用您的自定义验证器。 :)

    【讨论】:

    • 优秀的答案,详细的回应——正是我所需要的(加上一点保证)。
    • 很好的答案,当你有机会“greather_than”时请修正拼写错误。再次感谢。
    • @SimoneCarletti 您能否修改您的答案,这实际上在最近的 Rails 版本中是可能的,并且可以按预期工作。因此不再需要自定义验证器。
    • 在这一点上,鉴于问题没有用特定的 Rails 版本标记,这个答案是完全错误的。它声明“这行不通”,同时这是在现代版本的 Rails 中执行此操作的确切方法。
    【解决方案2】:

    validates_numericality_of 接受a large list of options,其中一些可以提供过程或符号(这意味着您基本上可以传递属性或整个方法)。

    验证一个属性的数值是否高于另一个值:

    class Project < ActiveRecord::Base
      validates_numericality_of :current_release, less_than: ->(project) { project.next_release }
    
      validates_numericality_of :next_release, 
        greater_than: Proc.new { project.current_release }
    end
    

    为了澄清,这些选项中的任何一个都可以接受一个过程或符号:

    • :greater_than
    • :greater_than_or_equal_to
    • :equal_to :less_than
    • :less_than_or_equal_to

    validates_numericality 文档: http://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of

    使用带有验证的 procs: http://guides.rubyonrails.org/active_record_validations.html#using-a-proc-with-if-and-unless

    【讨论】:

      【解决方案3】:

      使用 Rails 3.2,您可以通过传入 proc 来动态验证两个字段。

      validates_numericality_of :next_release, :greater_than => Proc.new {|project| project.current_release }
      

      【讨论】:

        【解决方案4】:

        这是执行自定义验证的最佳方式,但是,您可能希望研究类似 factory_girl 的东西来替代固定装置(看起来您正在使用):

        http://github.com/thoughtbot/factory_girl

        您的单元测试将如下所示:

        def test_...
            Factory.create(:project, :current_release => 10.0)
            assert !Factory.build(:project, :current_release => 1.0).valid?
        end 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-31
          • 2012-07-15
          • 1970-01-01
          • 2011-07-16
          • 2016-07-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多