Rails 4使用方法模拟自定义验证 - 在控制台中工作但在规范

时间:2015-07-24 21:51:18

标签: ruby-on-rails regex validation

尝试编写自定义模型验证并遇到一些麻烦。我正在使用正则表达式来确认十进制数量的验证格式如下:

  • 0到4之间的第一个数字
  • 格式为“#。##” - 即精度为3且比例为2的十进制数。我想要小数后面的2位数。
    • 零值没关系
    • 虽然这些值名义上是数字的,但我决定给列提供一个数据类型的字符串,以便更容易使用正则表达式进行比较,而不必费心使用#to_s方法。由于我不会对内容进行任何数学运算,这似乎是合乎逻辑的。

正则表达式已在Rubular上测试过 - 我对此非常有信心。我还在ruby控制台中定义了该方法,它似乎在那里工作正常。我已按照Rails Guides for Active Record Validations上的一般说明进行操作,但我仍然遇到让我头疼的验证问题。

以下是列的模型验证:bar -

class Foo < ActiveRecord::Base
  validate :bar_format

  def bar_format
    unless :bar =~ /^([0-4]{1}\.{1}\d{2})$/  || :bar == nil
      errors.add(:bar, "incorrect format")
    end
  end
end

Foo的规格:

require 'rails_helper'

describe Foo, type: :model do
  let(:foo) { build(:foo) }

  it "has a valid factory" do
    expect(foo).to be_valid
  end

  describe "bar" do
    it "can be nil" do
      foo = create(:foo, bar: nil)
      expect(foo).to be_valid
    end

    it "accepts a decimal value with precision 3 and scale 2" do
      foo = create(:foo, bar: "3.50")
      expect(foo).to be_valid
    end

    it "does not accept a decimal value with precision 4 and scale 3" do
      expect(create(:foo, bar: "3.501")).not_to be_valid
    end
  end
end

所有这些规格都无法在条形码上进行验证:

ActiveRecord::RecordInvalid:
       Validation failed: bar incorrect format

在ruby控制台中,我复制了方法bar_format,如下所示:

irb(main):074:0> def bar_format(bar)
irb(main):075:1>  unless bar =~ /^([0-4]{1}\.{1}\d{2})$/ || bar == nil
irb(main):076:2>   puts "incorrect format"
irb(main):077:2>  end
irb(main):078:1> end
=> :bar_format
irb(main):079:0> bar_format("3.50")
=> nil
irb(main):080:0> bar_format("0.0")
incorrect format
=> nil
irb(main):081:0> bar_format("3.5")
incorrect format
=> nil
irb(main):082:0> bar_format("3.1234")
incorrect format
=> nil
irb(main):083:0> bar_format("3.00")
=> nil

对于格式正确的条目,该方法返回nil,并返回错误格式化条目的错误消息。

怀疑这与验证逻辑有关,但据我所知,验证会查看错误哈希以确定项目是否有效。对于自定义方法,我的验证的逻辑结构与Rails指南中的示例中的结构相匹配。

*编辑* 感谢Lazarus建议我从:bar中删除冒号,因此它不是方法中的符号。在这之后,大多数测试通过。但是:我在两个我无法理解的测试中遇到了奇怪的失败。测试代码:

   it "does not accept a decimal value with precision 4 and scale 3" do
      expect(create(:foo, bar: "3.501")).not_to be_valid
    end

    it "generates an error message for an incorrect decimal value" do
      foo = create(:foo, bar: "4.506")
      expect(scholarship.errors.count).to eq 1
    end

将符号:bar转换为变量bar后,其他测试通过,但对于这两个测试,我得到:

Failure/Error: expect(create(:foo, bar: "3.501")).not_to be_valid
     ActiveRecord::RecordInvalid:
       Validation failed: 3 501 incorrect format

 Failure/Error: foo = create(:bar, min_gpa: "4.506")
     ActiveRecord::RecordInvalid:
       Validation failed: 4 506 incorrect format

为何将输入"3.501"转为3 501"4.506"4 506的任何想法?

2 个答案:

答案 0 :(得分:2)

在检查正则表达式或nil时使用符号而不是变量。

unless :bar =~ /^([0-4]{1}\.{1}\d{2})$/  || :bar == nil
  errors.add(:bar, "incorrect format")
end

:

中删除:bar

*编辑*

这不是规格失败,而是模型在创建时的验证。您应该使用build代替create

答案 1 :(得分:0)

不要使用符号来引用参数。

class Foo < ActiveRecord::Base
  validate :bar_format

  def bar_format
    unless bar =~ /^([0-4]{1}\.{1}\d{2})$/  || bar == nil
      errors.add(:bar, "incorrect format")
    end
  end
end

但是如果你想要一个十进制的正则表达式,如'1.0','1.11','1111.00',我建议你使用这个正则表达式:

/^\d+(\.\d{1,2})?$/

如果您可以使用正则表达式,这是:

/^(\d{1,3}\,){0,}(\d{1,3}\.\d{1,2})$/
祝你好运^^