неверное десятичное число становится 0,0 в рельсах - PullRequest
4 голосов
/ 18 мая 2011

У меня есть следующая модель рельсов:

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

Но когда я делаю следующее в консоли рельсов:

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

Как видите, я написал 'a' ион сохранил 0.0 в базе данных.Это почему?Это особенно раздражает, потому что это обходит мои проверки, например:

class Product < ActiveRecord::Base
  validates :price, :format => /\d\.\d/
end

Ответы [ 2 ]

5 голосов
/ 18 мая 2011

все, что недопустимо, преобразуется в 0.0, если вы вызываете to_f для него

"a".to_f #=> 0.0

вам нужно проверить это с проверками в модели

validates_numericality_of :price # at least in rails 2 i think

Я не знаю, что делает проверка по формату, поэтому я не могу вам помочь, но попробуйте проверить, что это число, RegExs проверяются только на строки, поэтому, если база данных является числовым полем, она может испортить

: формат предназначен для проверки почтовых символов, таких как адреса электронной почты, логины, имена и т. Д.,

3 голосов
/ 18 мая 2011

Вам нужно пересмотреть вопрос о том, что является вашей реальной проблемой.Особенностью Rails является то, что строка автоматически преобразуется либо в соответствующее десятичное значение, либо в 0.0 в противном случае.

Что происходит

1) Вы можете сохранитьчто-нибудь в поле ActiveRecord.Затем он преобразуется в соответствующий тип для базы данных.

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

2) Следует использовать правильную проверку, чтобы убедиться, что хранятся только действительные данные.Что-то не так с сохранением значения 0?Если нет, то вам не нужна проверка.

3) Вам не нужно проверять, что число будет храниться в базе данных.Поскольку вы объявили поле db десятичным, оно будет содержать ТОЛЬКО десятичные дроби (или ноль, если вы позволите полю иметь нулевые значения).

4) Ваша проверка была строковой проверкой.Таким образом, регулярное выражение проверки изменило значение 0.0 BigDecimal на "0.0", и оно прошло вашу проверку.Почему вы думаете, что ваша проверка была обойдена?

5) Почему именно вас беспокоит то, что другие программисты хранят строки в вашем ценовом поле?

Вы пытаетесь избежать ошибочной установки продуктов на нулевую цену? Есть несколько способов обойти это.Вы можете проверить значение по мере его поступления (до того, как оно будет преобразовано в десятичное), чтобы убедиться, что его формат правильный.См. AR Раздел «Перезапись доступа по умолчанию»

Но я думаю, что это будет грязно и подвержено ошибкам.Вы должны будете установить Error obj записи из Setter или использовать флаг.А простая проверка классов не сработает, помните, что данные формы всегда отображаются в виде строки.

Рекомендуется Вместо этого заставьте пользователя подтвердить, что он хотел установить цену 0 дляпродукт с использованием дополнительного поля только для AR (поле, которое не хранится в DBMS).

Например

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

Примечания Выше приведен видвещь, которую ОЧЕНЬ важно включить в свои тесты.

Также У меня были подобные ситуации в прошлом.В результате моего опыта я теперь записываю в базу данных имя человека, который сказал, что значение действительно должно быть $ 0 (или отрицательным), и пусть у них есть поле причины 255 символов для их обоснования.Позволяет сэкономить много времени, когда люди задаются вопросом, в чем причина.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...