我正在开发一个非常基本的购物车系统。
我有一个表items
,其中有一列price
type integer
。
对于包含欧元和美分的价格,我无法在我的视图中显示价格值。就在 Rails 框架中处理货币而言,我是否遗漏了一些明显的东西?
我正在开发一个非常基本的购物车系统。
我有一个表items
,其中有一列price
type integer
。
对于包含欧元和美分的价格,我无法在我的视图中显示价格值。就在 Rails 框架中处理货币而言,我是否遗漏了一些明显的东西?
您可能希望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
任何地方手动转换为 s 和从 s 转换,这可能会变得很痛苦。
正如 mcl 所指出的,要打印价格,请使用:
number_to_currency(price, :unit => "€")
#=> €1,234.01
这是一种利用composed_of
(ActiveRecord 的一部分,使用 ValueObject 模式)和 Money gem的精细、简单的方法
你需要
Product
integer
例如,模型(和数据库)中的列:price
把它写在你的product.rb
文件中:
class Product > ActiveRecord::Base
composed_of :price,
:class_name => 'Money',
:mapping => %w(price cents),
:converter => Proc.new { |value| Money.new(value) }
# ...
你会得到什么:
product.price = "$12.00"
自动转换为 Money 类product.price.to_s
显示十进制格式的数字(“1234.00”)product.price.format
显示货币格式正确的字符串product.price.cents.to_s
处理货币的常见做法是使用十进制类型。这是“使用 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
理智地检查你的价值观。
对于一些有抱负的 RoR 开发的初级/初学者来说,只需一点更新和所有答案的凝聚力,肯定会来到这里进行一些解释。
正如@molf: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
几点:
:decimal
将被用来BigDecimal
解决很多问题。
precision
并且scale
应该根据您所代表的内容进行调整
如果您处理接收和发送付款,precision: 8
并scale: 2
给您999,999.99
最高金额,这在 90% 的情况下都可以。
如果您需要表示财产或稀有汽车的价值,则应使用更高的precision
.
如果您使用坐标(经度和纬度),您肯定需要更高的scale
.
要生成具有上述内容的迁移,请在终端中运行:
bin/rails g migration AddPriceToItems price:decimal{8-2}
或者
bin/rails g migration AddPriceToItems 'price:decimal{5,2}'
正如这篇博文中所解释的那样。
告别额外的库并使用内置帮助程序。用作@molfnumber_to_currency
和@facundofarias 的建议。
要在 Rails 控制台中使用helper,请向's类number_to_currency
发送调用以访问 helper。ActiveSupport
NumberHelper
例如:
ActiveSupport::NumberHelper.number_to_currency(2_500_000.61, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
给出以下输出
2500000,61€
检查number_to_currency助手的另一个options
。
您可以将它放在应用程序助手中,并在视图中以任意数量使用它。
module ApplicationHelper
def format_currency(amount)
number_to_currency(amount, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
end
end
或者您可以将其作为实例方法放入Item
模型中,并在需要格式化价格的地方(在视图或助手中)调用它。
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
如果您使用的是 Postgres(因为我们现在是 2017 年),您可能想:money
尝试一下他们的列类型。
add_column :products, :price, :money, default: 0
使用money-rails gem。它可以很好地处理您模型中的货币和货币,并且还有一堆帮手来格式化您的价格。
使用虚拟属性(链接到修订(付费)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:虚拟属性:虚拟属性是一种添加不直接映射到数据库的表单字段的干净方法。在这里,我将展示如何处理验证、关联等。
绝对是整数。
即使 BigDecimal 在技术上存在1.5
,仍然会在 Ruby 中为您提供纯浮点数。
如果有人使用 Sequel,则迁移看起来像:
add_column :products, :price, "decimal(8,2)"
不知何故,续集忽略了 :precision 和 :scale
(续集版本:sequel (3.39.0, 3.38.0))
我的底层 API 都使用美分来表示金钱,我不想改变这一点。我也没有用大量资金工作。所以我只是把它放在一个辅助方法中:
sprintf("%03d", amount).insert(-3, ".")
这会将整数转换为至少包含三位数字的字符串(必要时添加前导零),然后在最后两位数字之前插入一个小数点,从不使用Float
. 从那里您可以添加适合您的用例的任何货币符号。
它肯定又快又脏,但有时这很好!
我以这种方式使用它:
number_to_currency(amount, unit: '€', precision: 2, format: "%u %n")
当然,货币符号、精度、格式等取决于每种货币。
您可以将一些选项传递给number_to_currency
(标准 Rails 4 视图助手):
number_to_currency(12.0, :precision => 2)
# => "$12.00"
Ruby & Rails 的简单代码
<%= number_to_currency(1234567890.50) %>
OUT PUT => $1,234,567,890.50