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...

2
  • 1
    Check out Rubular for testing Regex! rubular.com Commented Oct 31, 2016 at 17:51
  • The regex I've provided works as expected on Rubular. Commented Oct 31, 2016 at 18:04

4 Answers 4

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

Sign up to request clarification or add additional context in comments.

Comments

0

Try the following:

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

3 Comments

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?
Thanks for the feedback, taking a look!
@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
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}

1 Comment

While this code snippet may solve the question, including an explanation really helps 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.
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.