价格字段的单位转换

我们在存储一个产品的价格时,字段类型的设计可以有以下几种:

  • Decimal - 以元为单位存储浮点数

  • Integer - 以分为单位储存整数

如果用浮点数存储数据,那么我们在表单中录入价格时,时常会遇到一个奇怪的现象,录入的价格是912.00元,而存储数据库时莫名其妙地变成了911.999999999999 。呈现到前端时,就很怪异了。

在ruby中我可以通过下面测试,发现同样问题:

2.3.4 :017 > "9.12".to_f * 100
 => 911.9999999999999

因此,我们就有了以分为单位存储的想法。但是,以分为单位,我们在生成表单时,又想让用户以元为单位录入价格,我们可能会这么做:

rails g scaffold product name price_cents:integer
app/models/product.rb
class Product < ApplicationRecord
    # 数据库存储价格字段是 price_cents,整形,单位为分
    def price
        (price_cents || 0) / 100.0
    end

    def price=(v)
        # 这里用.round就是为了解决上面的911.99999999问题
        self.price_cents = (v.to_f * 100).round
    end
end

封装一下代码,做到足够DRY

以上代码,足够应付我们的价格前后端单位转换问题。如果需要更高级的功能,我们可以尝试Gem moneymoney-rails

Last updated