我正在开发一个非常基本的购物车系统。
我有一个表items,它的列价格类型为整型。
我在视图中显示包含欧元和美分的价格时遇到了麻烦。在Rails框架中处理货币时,我是否遗漏了一些明显的东西?
我正在开发一个非常基本的购物车系统。
我有一个表items,它的列价格类型为整型。
我在视图中显示包含欧元和美分的价格时遇到了麻烦。在Rails框架中处理货币时,我是否遗漏了一些明显的东西?
当前回答
你可以将一些选项传递给number_to_currency(一个标准的Rails 4视图帮助器):
number_to_currency(12.0, :precision => 2)
# => "$12.00"
由Dylan Markow发布
其他回答
您可能希望在数据库中使用DECIMAL类型。在迁移过程中,执行如下操作:
# 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
在Rails中,:decimal类型返回为BigDecimal,这对于价格计算非常有用。
如果您坚持使用整数,那么您将不得不在所有地方手动转换为bigdecimal,这可能会成为一个麻烦。
正如mcl所指出的,要打印价格,请使用:
number_to_currency(price, :unit => "€")
#=> €1,234.01
只是对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
我是这样用的:
number_to_currency(amount, unit: '€', precision: 2, format: "%u %n")
当然,货币的符号、精度、格式等都取决于每种货币。
处理货币的常见做法是使用十进制类型。 下面是“使用Rails进行敏捷Web开发”中的一个简单示例。
add_column :products, :price, :decimal, :precision => 8, :scale => 2
这将允许您处理从-999,999.99到999,999.99的价格 你可能还想在你的项目中包括一个验证,比如
def validate
errors.add(:price, "should be at least 0.01") if price.nil? || price < 0.01
end
检查你的价值观。
使用Virtual Attributes(链接到修订的(付费)Railscast),您可以将price_in_cents存储在一个整数列中,并在您的产品模型中添加虚拟属性price_in_dollars作为getter和setter。
# Add a price_in_cents integer column
$ rails g migration add_price_in_cents_to_products price_in_cents:integer
# Use virtual attributes in your Product model
# app/models/product.rb
def price_in_dollars
price_in_cents.to_d/100 if price_in_cents
end
def price_in_dollars=(dollars)
self.price_in_cents = dollars.to_d*100 if dollars.present?
end
来源:RailsCasts #016:虚拟属性:虚拟属性是添加不直接映射到数据库的表单字段的一种干净的方式。在这里,我将展示如何处理验证、关联等。