Rails正则表达式验证在rspec中失败

时间:2014-10-21 15:06:32

标签: ruby-on-rails regex rspec

我正在尝试编写和测试一个正则表达式的valiation,它只允许一系列成对的整数,格式为

n,n n,n 

其中n是不以零开头的任何整数,并且对是空格分隔的。可能只有一对,或者字段也可能是空的。

因此,对于这些数据,它应该给出2个错误

12,2 11,2 aa 111,11,11
  • 错误1:' aa'
  • 错误2:三联体(111,11,11)

在我的Rails模型中,我有这个

validates_format_of :sequence_excluded_region, :sequence_included_region, 
                  with: /[0-9]*,[0-9] /, allow_blank: true 

在我的Rspec模型测试中,我有这个

 it 'is invalid with alphanumeric SEQUENCE_INCLUDED_REGION' do
    expect(DesignSetting.create!(sequence_included_region: '12,2 11,2 aa 111,11,11')).to have(1).errors_on(:sequence_included_region)                  
 end

测试失败,因为正则表达式没有找到错误,或者我可能错误地调用了测试。

Failures:

  1) DesignSetting is invalid with alphanumeric SEQUENCE_INCLUDED_REGION
     Failure/Error: expect(DesignSetting.create!(sequence_included_region: '12,2 11,2 aa 111,11,11')).to have(2).errors_on(:sequence_included_region)
       expected 2 errors on :sequence_included_region, got 0
     # ./spec/models/design_setting_spec.rb:5:in `block (2 levels) in <top (required)>'

2 个答案:

答案 0 :(得分:1)

(?<=\s|^)\d+,\d+(?=\s|$)

尝试使用empty string替换。由拆分的左侧字符串是您的错误。

参见演示。

http://regex101.com/r/rQ6mK9/22

答案 1 :(得分:1)

正则表达式

你的正则表达式匹配一对,后跟字符串中的空格 where

'12,2 11,2 aa 111,11,11 13,3'.scan /[0-9]*,[0-9] /
=> ["12,2 ", "11,2 "]

因此任何带有一个有效对后跟空格的字符串都是有效的。此外,由于没有空间,单个对将失败3,4

将验证整个字符串的正则表达式:

positive_int = /[1-9][0-9]*/
pair = /#{positive_int},#{positive_int}/

re_validate = /
  \A                  # Start of string
  #{pair}             # Must have one number pair. 
  (?:\s#{pair})*      # Can be followed by any number of pairs with a space delimiter
  \z                  # End of string (no newline)
/x

校验

我不使用rails很多,但是你似乎期望从一个简单的正则表达式验证器中为它解析字符串中的各个错误组件。

如果你按空格分割变量,然后验证数组的每个元素,你就可以获得每个字段的详细信息。

'12,2 11,2 aa 111,11,11 13,3'.split(' ').reject{|f| f =~ /^[1-9][0-9]*,[1-9][0-9]*$/ }

您可以使用validates_with将类似内容放入自定义验证程序类中,然后您可以直接控制errors ...

class RegionValidator < ActiveModel::Validator
  def validate(record)
    record.sequence_included_region.split(' ').reject{|f| f =~ /^[1-9][0-9]*,[1-9][0-9]*$/ }.each do |err|
      record.errors[sequence_included_region] << "bad region field [#{err}]"
    end
  end
end