読者です 読者をやめる 読者になる 読者になる

Rails 4.2 に移行していて decimal 型の属性のバリデーションで嵌った

ruby rails

例えば、decimal 型の weight という属性を持つ Item クラスがあるとする。

class Item < ActiveRecord::Base
  validates :weight, inclusion: { in: [0.2, 0.4, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0] }
end

Rails 4.1.2 までは下記のようなバリデーションが成功していたのに、 4.2.0 に上げたら失敗するようになった。

item = Item.new(weight: 1.2)
item.valid? #=> false
item.weight #=> #<BigDecimal:7f0319279bd8,'0.1199999999 9999999555 9107901499 3738383E1',45(54)>

環境は次の通り。

decimal 型の属性は BigDecimal で保持するみたいで、 初期値として渡した Float の値を BigDecimal に変換した結果、誤差が発生してしまっていた。

BigDecimal は文字列から作成できるので

item = Item.new(weight: "1.2")
item.valid? #=> true
item.weight #=> #<BigDecimal:7f031937dbd8,'0.12E1',18(18)>

という風に文字列でセットして回避。