port5432
port5432

Reputation: 6371

Rails regex validation failing in rspec

I am trying to write and test a regex valiation which allows only for a sequence of paired integers, in the format

n,n n,n 

where n is any integer not beginning with zero and pairs are space separated. There may be a single pair or the field may also be empty.

So with this data, it should give 2 errors

12,2 11,2 aa 111,11,11

In my Rails model I have this

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

In my Rspec model test I have this

 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

The test fails, as the regex does not find the errors, or perhaps I am calling the test incorrectly.

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)>'

Upvotes: 1

Views: 437

Answers (2)

Matt
Matt

Reputation: 74660

Regex

Your regex matches a single pair followed by a space anywhere in the string.

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

So any string with one valid pair followed by a space will be valid. Also a single pair would fail 3,4 as there is no space.

A regex that would validate the entire string:

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

Validators

I don't use rails much but it seems like you are expecting too much from a simple regex validator for it to parse out the individual error components from a string for you.

If you split the variable up by space and then validated each element of the array you could get that detail for each field.

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

You can put something like that into a custom validator class using validates_with which you can then have direct control of your errors with...

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

Upvotes: 1

vks
vks

Reputation: 67968

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

Try this.Replace with empty string.The left string split by are your errors.

See demo.

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

Upvotes: 1

Related Questions