【问题标题】:Money-Rails is discarding price amount after decimal pointMoney-Rails 在小数点后丢弃价格金额
【发布时间】:2018-03-07 16:34:03
【问题描述】:

我正在构建 Rails 5 API,我试图在其中发送金额并将其存储在 PostgresQL 数据库中。我发送的金额为 2.4,但我在数据库中看到仅存储了 2 个。我做错了什么?

我的迁移:

class CreateTransactions < ActiveRecord::Migration[5.1]
  def change
  create_table :transactions do |t|
   t.monetize :transaction_price, amount: { null: true, default: nil }
   t.timestamps
  end
 end
end

我的模型是:

class Transaction < ApplicationRecord
  monetize :transaction_price_cents
end

我的控制器:

class TransactionsController < ApiController
      def create
        transaction = Transaction.new(transaction_param)
        if transaction.save
          render json: { status: 'SUCCESS', data:transaction }, status: :ok
        end
      end

      private
      def transaction_param
        params.require(:transaction).permit(:transaction_price_cents)
      end
end

我正在用邮递员发送这个 json:

{
    "transaction_price_cents": 345.23
}

我得到的回应:

{
    "status": "SUCCESS",
    "data": {
        "id": 1,
        "transaction_price_cents": 345,
        "transaction_price_currency": "USD",
    }
}

我想要 345.23 或 34523,但它只给我 345!

【问题讨论】:

  • 如果你想用美元做逻辑,金额不应该大 100 倍吗?它甚至在与值 transaction_price_cent 关联的名称中。
  • 我完全明白。您的意思是在将价格发送到数据库之前,我必须将价格乘以 100(我的意思是使其成为美分)?我认为 Gem 会为我做到这一点。

标签: ruby-on-rails ruby rubygems ruby-on-rails-5 money-rails


【解决方案1】:

您的价格(美分)!没关系!

以美分处理货币是一种常见的模式。当涉及税收或货币兑换的四舍五入错误时,它还将挽救您的生命。就像在他们的文档中提到的那样,您应该使用帮助器以人类可读的形式输出价格:

humanized_money @money_object                       # => 6.50
humanized_money_with_symbol @money_object           # => $6.50
money_without_cents_and_with_symbol @money_object   # => $6

如果您通过 API 访问数据,您可以在您的 api 中添加人类可读字段

def transaction_price_human_readable
  return humanized_money_with_symbol(@money_object) # or self or...
end

保存/创建模型:如果您得到一个浮点数,您可以将浮点数更改为美分 before_save

before_save :convert_transaction_price
def convert_transaction_price
   self.transaction_price = (self.transaction_price * 100).to_i
end

【讨论】:

  • 那么,当我发送价格时,我应该以美分发送吗?如果我有 345.23 美元,那么我必须像 43523 一样发送它?你是这个意思吗?
  • 是的,您还必须以美分保存价格。您可以在 before_save 操作中执行此操作
  • 您还应该检查您的迁移。在文档中,他们在属性名称中提到了“*_cents”...
  • 嗨,我试过这个before_save :convert_transaction_price def convert_transaction_price self.transaction_price = (self.transaction_price * 100).to_i end 但它仍然显示错误的值。现在,它显示的是 23400 而不是 23423。我错过了什么吗?
  • 其实我也有这个问题:github.com/RubyMoney/money-rails/issues/396你有什么解决办法吗?
【解决方案2】:

我遇到了同样的问题。
(编辑后的新答案和正确答案):

我所要做的就是使用 money-rails gem 提供的属性。在我的例子中,我有一个amount_cents 属性,我必须在表单中使用提供的:amount 属性。

<%= f.label :amount %>
<%= f.text_field :amount %>

注意:我将:amount_cents 的值转换为edit.html.erb 中的浮点字符串,如下所示:

<%= f.label :amount %>
<%= f.text_field :amount, value: number_with_precision(f.object.amount_cents / 100, precision: 2).gsub(/\./, ',') %>

另请注意,我已将money-rails 配置为使用使用“,”作为分隔符的欧元,这就是为什么我必须使用.gsbu(/\./, ',')

这里是重要部分,我必须在控制器中更新我的 strong_parameters 以允许:amount,而不是:amount_cents

    private

        def invoice_params
            params.require(:invoice).permit(…, :amount, …)
        end     

--

(旧答案):
我得出的结论是最好直接在前端将输入值更改为美分。然后将美分发送到后端。

这是一个很好的刺激控制器,它可以做到这一点:https://gist.github.com/psergi/72f99b792a967525ffe2e319cf746101
(您可能需要根据自己的喜好更新该要点,并且它还希望您在 Rails 项目中使用 Stimulus)

(我将旧答案留在此处,因为我认为将_cents从前端发送到后端是一个好习惯,但目前[对我而言]没有必要。如果您想支持超过一种货币,您可能想这样做并使用 .js 框架来处理输入转换 -> s.th. 比如 http://autonumeric.org/)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 1970-01-01
    • 2022-07-12
    • 1970-01-01
    相关资源
    最近更新 更多