34

What is the best way to validate a cost/price input by a user, validation rules below:

  • Examples of formats allowed .23, .2, 1.23, 0.25, 5, 6.3 (maximum of two digits after decimal point)
  • Minimum value of 0.01
  • Maximum value of 9.99
freshest
  • 6,229
  • 9
  • 35
  • 38

3 Answers3

69

Check the price and verify the format

#rails 3    
validates :price, :format => { :with => /\A\d+(?:\.\d{0,2})?\z/ }, :numericality => {:greater_than => 0, :less_than => 10}

#rails 2
validates_numericality_of :price, :greater_than => 0, :less_than => 10    
validates_format_of :price, :with => /\A\d+(?:\.\d{0,2})?\z/
rwilliams
  • 21,188
  • 6
  • 49
  • 55
  • 1
    That's cool that in rails3 you can validate as both the original string and as a number. However, I can't quite see why you're using the ?: assertion here. Surely the ? after the decimal part takes care of the "it's optional" thing? – noodl Nov 13 '10 at 21:47
  • If anything you'd want a look-behind assertion there so that 1. (decimal point with no following digits) is invalid? Perhaps I'm just not seeing it :) – noodl Nov 13 '10 at 21:50
  • 4
    Take care when you use `:greater_than => 0`. If the database field is for example a decimal with a precision of 2, the validation will still allow a value of 0.00001, which will be saved in the table as 0. – Majiy Mar 09 '12 at 22:44
  • 3
    Indeed, you should not use `:greater_than => 0` for @Majiy's above mentioned reason, rather use `:greater_than_or_equal_to => 0.01`. – user664833 Mar 30 '12 at 03:14
  • 3
    I think you both are missing the fact that the regex will also catch stuff like 0.00001 – rwilliams Mar 30 '12 at 05:25
  • 1
    This works well, and returns `nil` for more than 2 decimal places: `/\A\d+(?:\.\d{0,2})?\z/` – Michael De Silva Apr 30 '12 at 09:13
  • I use :with => /^\d+??(?:\.\d{0,2})?$/ } then display error: SyntaxError: invalid quantifier – harsh4u May 22 '14 at 07:30
  • Thanks....Works for me this: :format => { :with => /\A\d+(?:\.\d{0,2})?\z/ }, :numericality => {:greater_than => 0, :less_than => 10} – harsh4u May 22 '14 at 07:39
  • I did some testing and I can't see an advantage of using the lookahead over a normal group like `/\A\d+(\.\d{0,2})?\z/`. Is there an edge case I'm missing? – MCB May 03 '16 at 23:36
4

For client side validations you can use a jQuery plugin like this one that allows you to define different valid formats for a given input.

For server side validations and according to this question/answer maybe you should use a decimal column for price in which you can define values for precision and scale, scale solves the two digits after decimal point restriction.

Then to validate the numericality, minimum and maximum value you can use the next validation method:

validates_numericality_of :price, :greater_than => 0, :less_than => 10
Community
  • 1
  • 1
jpemberthy
  • 7,473
  • 8
  • 44
  • 52
  • 1
    SQLite 3 ignores the precision and scale arguments and so this will not stop user entering 4.555 – freshest Nov 13 '10 at 17:16
  • You should not use `:greater_than => 0` for the reason @Majiy mentioned, rather use `:greater_than_or_equal_to => 0.01`. – user664833 Mar 30 '12 at 03:15
2

You can build custom validations.Lets say, for example the second case:

validate :price_has_to_be_greater_than_minimum

def price_has_to_be_greater_than_minimum
  errors.add(:price, "price has to be greater than 0.01") if
  !price.blank? and price > 0.01
end

More on this, in the Rails Guides, here.

Rimian
  • 36,864
  • 16
  • 117
  • 117
Shreyas
  • 8,737
  • 7
  • 44
  • 56
  • 2
    There is no reason to write a custom validation when Rails provides one out-of-the-box for this: `validates :price, :numericality => { :greater_than => 0.01, :allow_blank => true }`. Same with the first validation--you are validating against a Regexp, which Rails provides already using `validates :price, :format => ...` – Isaac Betesh Apr 29 '14 at 14:04