views:

136

answers:

2

I was trying to write a validation for Rails to ensure that a price entered on a form was greater than zero. It works…sort of. The problem is that when I run it, val is turned into an integer, so it thinks that .99 is less than .1. What's going on, and how should I fix the code?

class Product < ActiveRecord::Base
  protected
    def self.validates_greater_than_zero(*attr_names)
      validates_each(attr_names) do |record, attr, val|
        record.errors.add(attr, "should be at least 0.01 (current val = #{val.to_f})") if val.nil? || val < 0.01
      end
    end
  public
  validates_presence_of :title, :description, :image_url
  validates_numericality_of :price
  validates_greater_than_zero :price
end
+2  A: 

If the original string value is cast to an integer, it will be rounded down. So “0.99” gets rounded down to 0, which is obviously less than 0.01. You should compare against the original string, which you can get from the <attr>_before_type_cast method.

Something like this should work:

validates_each(attr_names) do |record, attr, val|
  if record.send("#{attr}_before_type_cast").to_f < 0.01
    record.errors.add(attr, "error message here")
  end
end
Todd Yandell
Thanks so much.
+2  A: 

You can change

validates_numericality_of :price

to

validates_numericality_of :price, :greater_than_or_equal_to => 0.01

it seems to do what your validates_greater_than_zero validator wants to do.

Corey
Thanks so much—that'll help me to write better code in the future.