1

In a Rails 5 validation, I'm trying to ensure that an inputted float have at most 3 digits after the decimal. Partly following this thread I have

validates :modifier, presence: true, format: { with: /\A\d+(?:\.\d{0,3})?\z/ }, numericality: { less_than: 100_000}

But the following test fails (using the shoulda matchers gem):

should_not allow_value(12345.1234).for(:modifier)

Error message: Expected errors when modifier is set to 12345.1234, got no errors

Even though the following tests succeed:

should allow_value(12345.123).for(:modifier) should allow_value(12345).for(:modifier) should_not allow_value(123456).for(:modifier)

Probably it has something to do with the regex only working for a string, whereas the :modifier attribute I'm working with is coming in as a float. So I need to find a way to run the validation on a stringified version of the float...

Community
  • 1
  • 1
Jay Quigley
  • 133
  • 1
  • 2
  • 6

4 Answers4

1

The issue was that Rails was doing automatic typecasting given that my database had set the column as decimal, precision: 5, scale: 3.

In order to validate the input properly, I needed to run this validation:

validates :modifier_before_type_cast, presence: true, format: { with: /\A\d+(?:\.\d{0,3})?\z/ }, numericality: { less_than: 100_000 }

My most relevant help ended up coming from here: validation before attribute setters can type cast

Community
  • 1
  • 1
Jay Quigley
  • 133
  • 1
  • 2
  • 6
0

Try the following:

validates :modifier, presence: true, format: { with: /\A\d+(\.\d{0,3})?$/ }, numericality: { less_than: 100_000}
Sara Fuerst
  • 5,688
  • 8
  • 43
  • 86
  • The failing test still fails, and also the 123456 test fails. And here's an important error message (I'm using Rails 5): ```ArgumentError: The provided regular expression is using multiline anchors (^ or $), which may present a security risk. Did you mean to use \A and \z, or forgot to add the :multiline => true option?``` – Jay Quigley Oct 31 '16 at 18:03
  • Thanks for the feedback, taking a look! – Sara Fuerst Oct 31 '16 at 18:10
  • @JayQuigley try what I've updated it to. The 123456 test is passing when I test it, so let me know if it isn't for you – Sara Fuerst Oct 31 '16 at 18:14
0

It seems like regex in your validates doesn't work.

This expression works

/\A\d+(?:\.?\d{0,3})\z/

in model

validates :modifier, presence: true, format: { with: /\A\d+(?:\.?\d{0,3})\z/ }, numericality: { less_than: 100_000}
Oleh Sobchuk
  • 3,612
  • 2
  • 25
  • 41
  • 1
    While this code snippet may solve the question, including an explanation [really helps](//meta.stackexchange.com/q/114762) to improve the quality of your post. Remember that you are answering the question for readers in the future, not just the person asking now! Please [edit] your answer to add explanation, and give an indication of what limitations and assumptions apply. – Toby Speight Nov 08 '16 at 13:58
0

This one works for many countries and you can write it with or without spaces (\s*):

validates :bank_account, allow_blank: true, uniqueness: true, format: { with: /\A[a-zA-Z]{2}[0-9]{2}\s*[a-zA-Z0-9]{4}\s*[0-9]{4}\s*([a-zA-Z0-9]?){0,12}\s*[0-9]{4}\z/}

This is a non-exhaustive list of countries it works for: Belgium, Croatia, France, Germany, Luxembourg, Netherlands, Poland, Romania, Spain. I checked it online with this useful tool https://regexr.com/

One of the countries it doesn't work for is Bulgaria for example.

RobertEagle
  • 83
  • 1
  • 9