我正在开发一个非常基本的购物车系统。

我有一个表items,它的列价格类型为整型。

我在视图中显示包含欧元和美分的价格时遇到了麻烦。在Rails框架中处理货币时,我是否遗漏了一些明显的东西?


当前回答

下面是一个利用composed_of (ActiveRecord的一部分,使用ValueObject模式)和Money宝石的简单方法

你需要

金钱宝石(4.1.0版本) 一个模型,例如Product 模型(和数据库)中的整数列,例如:price

把这些写进你的产品中。rb文件:

class Product > ActiveRecord::Base

  composed_of :price,
              :class_name => 'Money',
              :mapping => %w(price cents),
              :converter => Proc.new { |value| Money.new(value) }
  # ...

你会得到:

Without any extra changes, all of your forms will show dollars and cents, but the internal representation is still just cents. The forms will accept values like "$12,034.95" and convert it for you. There's no need to add extra handlers or attributes to your model, or helpers in your view. product.price = "$12.00" automatically converts to the Money class product.price.to_s displays a decimal formatted number ("1234.00") product.price.format displays a properly formatted string for the currency If you need to send cents (to a payment gateway that wants pennies), product.price.cents.to_s Currency conversion for free

其他回答

你可以将一些选项传递给number_to_currency(一个标准的Rails 4视图帮助器):

number_to_currency(12.0, :precision => 2)
# => "$12.00"

由Dylan Markow发布

绝对的整数。

即使BigDecimal技术上存在,1.5仍然会在Ruby中给你一个纯浮点数。

我的底层api都使用美分来表示钱,我不想改变这一点。我也没有大量的资金。我把这个放到helper方法中

sprintf("%03d", amount).insert(-3, ".")

它将整数转换为至少有三位数字的字符串(必要时添加前导零),然后在最后两位数字之前插入一个小数点,从不使用Float。从这里,您可以添加任何适合您的用例的货币符号。

这绝对是快速和肮脏的,但有时这是好的!

下面是一个利用composed_of (ActiveRecord的一部分,使用ValueObject模式)和Money宝石的简单方法

你需要

金钱宝石(4.1.0版本) 一个模型,例如Product 模型(和数据库)中的整数列,例如:price

把这些写进你的产品中。rb文件:

class Product > ActiveRecord::Base

  composed_of :price,
              :class_name => 'Money',
              :mapping => %w(price cents),
              :converter => Proc.new { |value| Money.new(value) }
  # ...

你会得到:

Without any extra changes, all of your forms will show dollars and cents, but the internal representation is still just cents. The forms will accept values like "$12,034.95" and convert it for you. There's no need to add extra handlers or attributes to your model, or helpers in your view. product.price = "$12.00" automatically converts to the Money class product.price.to_s displays a decimal formatted number ("1234.00") product.price.format displays a properly formatted string for the currency If you need to send cents (to a payment gateway that wants pennies), product.price.cents.to_s Currency conversion for free

只是对RoR开发中一些有抱负的初级/初学者的所有答案进行了一点更新和整合,这些答案肯定会在这里得到一些解释。

与金钱打交道

使用:decimal在DB中存储货币,就像@molf建议的那样(也是我的公司在处理货币时使用的黄金标准)。

# precision is the total number of digits
# scale is the number of digits to the right of the decimal point
add_column :items, :price, :decimal, precision: 8, scale: 2

几个点:

:decimal is going to be used as BigDecimal which solves a lot of issues. precision and scale should be adjusted, depending on what you are representing If you work with receiving and sending payments, precision: 8 and scale: 2 gives you 999,999.99 as the highest amount, which is fine in 90% of cases. If you need to represent the value of a property or a rare car, you should use a higher precision. If you work with coordinates (longitude and latitude), you will surely need a higher scale.

如何生成迁移

要生成带有上述内容的迁移,在terminal中运行:

bin/rails g migration AddPriceToItems price:decimal{8-2}

or

bin/rails g migration AddPriceToItems 'price:decimal{5,2}'

正如这篇博客文章所解释的。

货币格式

和额外的库说再见,使用内置的helper。请按照@molf和@facundofarias的建议使用number_to_currency。

要在Rails控制台中使用number_to_currency助手,请向ActiveSupport的NumberHelper类发送一个调用,以便访问这个助手。

例如:

ActiveSupport::NumberHelper.number_to_currency(2_500_000.61, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")

给出以下输出

2500000,61€

检查number_to_currency助手的其他选项。

放在哪里

您可以将它放在应用程序助手中,并在视图中任意使用它。

module ApplicationHelper    
  def format_currency(amount)
    number_to_currency(amount, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
  end
end

或者,您可以将它作为实例方法放在Item模型中,并在需要格式化价格的地方(在视图或helper中)调用它。

class Item < ActiveRecord::Base
  def format_price
    number_to_currency(price, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
  end
end

并且,我如何在控制器内使用number_to_currency的示例(注意negative_format选项,用于表示退款)

def refund_information
  amount_formatted = 
    ActionController::Base.helpers.number_to_currency(@refund.amount, negative_format: '(%u%n)')
  {
    # ...
    amount_formatted: amount_formatted,
    # ...
  }
end