如何修复Rails中这种奇怪的舍入错误?

时间:2013-03-31 18:19:46

标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-3.2

我最近在Rails中遇到了这个奇怪的错误。

class PaymentsController < ApplicationController

  def new
    @payment = current_user.payments.build(:invoice_id => params[:invoice_id])
    @title = "Make payment" 
  end

end

class Payment < ActiveRecord::Base

  attr_accessible :amount, :date, :invoice_id

  after_initialize :set_amount

  private

  def set_amount
    if new_record? && invoice.present?
      self.amount ||= invoice.amount_payable
    end
  end

end

当我从invoice调用此操作时,就像这样...

<%= link_to "Make payment", new_payment_path(:invoice_id => invoice.id) %>

...付款方式会在下拉字段中显示正确的invoice(这是正确的)。

付款amount在所有情况的约90%中填入了正确的金额。

但是,有时它没有填充数据库中的2位数amount_payable,而是填充其他一些奇怪的值,例如:

87.31999999999999

(其中87.32是存储在SQLite数据库中的十进制类型值)

有人可以告诉我导致这种舍入错误的原因还是指向了正确的方向?

感谢您的帮助。

顺便说一句,这是我的数据库架构:

create_table "invoices", :force => true do |t|
  t.decimal  "amount_payable", :precision => 8, :scale => 2
end

1 个答案:

答案 0 :(得分:5)

你永远不应该将Money存储为浮点数 - 这里发生的是浮点算术,这对于用钱计算是很常见的。

更好的一点是将所有内容存储为整数美分。因此,您可能在数据库中有一个“amount_in_cents”列,它是一个整数。

然后,为“金额”添加一个getter / setter,以便在整个地方使用#amount

class Payment < ActiveRecord::Base

  def amount
    amount_in_cents / 100.0
  end

  def amount=(other)
    self.amount_in_cents = (other * 100).to_i
  end
end