Invalid decimal is 0.0 in rails

I have the following rail model:

class Product < ActiveRecord::Base end class CreateProducts < ActiveRecord::Migration def self.up create_table :products do |t| t.decimal :price t.timestamps end end def self.down drop_table :products end end 

But when I do the following in the rails console:

 ruby-1.9.2-p180 :001 > product = Product.new => #<Product id: nil, price: nil, created_at: nil, updated_at: nil> ruby-1.9.2-p180 :002 > product.price = 'a' => "a" ruby-1.9.2-p180 :003 > product.save => true ruby-1.9.2-p180 :004 > p product #<Product id: 2, price: #<BigDecimal:39959f0,'0.0',9(9)>, created_at: "2011-05-18 02:48:10", updated_at: "2011-05-18 02:48:10"> => #<Product id: 2, price: #<BigDecimal:3994ca8,'0.0',9(9)>, created_at: "2011-05-18 02:48:10", updated_at: "2011-05-18 02:48:10"> 

As you can see, I wrote "a" and it saved 0.0 in the database. Why is this? This is especially annoying because it circumvents my checks, for example:

 class Product < ActiveRecord::Base validates :price, :format => /\d\.\d/ end 
+4
source share
2 answers

everything that is invalid gets a value of 0.0 if you call to_f on it

"a".to_f #=> 0.0

you will need to check it with validations in the model

validates_numericality_of :price # at least in rails 2 i think

I don’t know what format validation does, so I can’t help you there, but try to check that it is a number, RegExs are checked only for strings, so if the database is a field with numbers, it can be corrupted

: the format is for things like email addresses, logins, names, etc., to check for inert characters and such

+5
source

You need to take a look at your real problem again. A feature of Rails is that the string is automatically converted automatically either to the corresponding decimal value, or to 0.0 otherwise.

What's happening

1) You can store anything in the ActiveRecord field. Then it is converted to the appropriate type for the database.

 >> product.price = "a" => "a" >> product.price => #<BigDecimal:b63f3188,'0.0',4(4)> >> product.price.to_s => "0.0" 

2) You must use the correct check to make sure that only reliable data is saved. Is there something wrong with keeping the value 0? If not, then you do not need verification.

3) You do not need to verify that the number will be stored in the database. Since you declared the db field to be a decimal field, it will ONLY contain decimal numbers (or null if you give the field null values).

4) Your check was oriented to the check line. Thus, the validation regular expression changed 0.0 BigDecimal to "0.0" and it passed validation. Why do you think your check has been ruled out?

5) Why are you worried that other programmers store strings in your price field?

Are you trying to avoid the erroneous price at zero price? There are several ways around this. You can check the value as it arrives (before it is converted to decimal) to see if its format is correct. See AR Section “Overwriting Default Accessories”

But I think it would be dirty and error prone. You will need to set an error record from the Setter object or use a flag. And a simple class check will not work, remember that form data is always included in the string.

Recommended . Instead, ask the user to confirm that they are designed to set the price to 0 for the product using the optional AR-only field (a field that is not stored in dbms).

For instance,

 attr_accessor :confirm_zero_price # Validate that when the record is created, the price # is either > 0 or (price is <= 0 && confirm_zero_price) validates_numericality_of :price, :greater_than => 0, :unless => Proc.new { |s| s.confirm_zero_price}, :on => :create 

Notes The above thing, which is VERY important for inclusion in your tests.

Also I have had similar situations in the past. As a result of my experience, I now record in the database the name of the person who said that the value should really be $ 0 (or negative), and let them have a 255 char reason field to justify them. Saves a lot of time later when people are wondering what is the reason.

+3
source

All Articles