提问



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


我有一个表items,它有一个integer类型的列price


我无法在我的观点中显示包含欧元和美分的价格的价格值。在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的所有地方,这可能只是一个痛苦。


正如mcl所指出的,要打印价格,请使用:


number_to_currency(price, :unit => "€")
#=> €1,234.01

其它参考1


这是一个很好的,简单的方法,利用composed_of(ActiveRecord的一部分,使用ValueObject模式)和Money gem


你需要



  • Money gem(版本4.1.0)

  • 一个模型,例如Product

  • 模型(和数据库)中的integer列,例如:price



product.rb文件中写下:[33]


class Product > ActiveRecord::Base

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


你会得到什么:



  • 如果没有任何额外的更改,您的所有表单都会显示美元和美分,但内部表示仍然只是美分。表单将接受$ 12,034.95之类的值并将其转换为您。您无需在模型中添加额外的处理程序或属性,也无需在视图中添加帮助程序。

  • product.price = "$12.00"自动转换为Money类

  • product.price.to_s显示十进制格式的数字(1234.00)

  • product.price.format显示货币格式正确的字符串

  • 如果您需要发送美分(到需要便士的支付网关),product.price.cents.to_s

  • 免费提供货币转换


其它参考2


处理货币的常用做法是使用十进制类型。
以下是使用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 


理智 - 检查你的价值观。

其它参考3


使用money-rails gem。它很好地处理你的模型中的货币和货币,还有一堆帮助器来格式化你的价格。[34]

其它参考4


使用虚拟属性(链接到修订(付费)Railscast),您可以将price_in_cents存储在整数列中,并在产品模型中添加虚拟属性price_in_dollars作为getter和setter。[35]


# 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:虚拟属性:虚拟属性是添加不直接映射到数据库的表单字段的简洁方法。在这里,我将展示如何处理验证,关联等。 [36]

其它参考5


如果您正在使用Postgres(并且因为我们现在在2017年)您可能想要尝试他们的:money列类型。


add_column :products, :price, :money, default: 0

其它参考6


绝对是整数。[37]


即使BigDecimal在技术上存在1.5仍然会在Ruby中为您提供纯粹的Float。

其它参考7


如果有人使用续集,迁移将看起来像:


add_column :products, :price, "decimal(8,2)"


不知怎的,Sequel忽略了:精度和:规模


(续集版本:续集(3.39.0,3.38.0))

其它参考8


我这样使用它:


number_to_currency(amount, unit: '€', precision: 2, format: "%u %n")


当然,货币符号,精度,格式等取决于每种货币。

其它参考9


您可以将一些选项传递给number_to_currency(标准的Rails 4视图助手):


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


由Dylan Markow发布

其它参考10


我的底层API都使用美分代表金钱,我不想改变它。我也没有用大笔资金。所以我只是把它放在一个辅助方法中:


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


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


它肯定快速而肮脏,但有时候那很好!

其它参考11


Ruby&的简单代码轨道


<%= number_to_currency(1234567890.50) %>

OUT PUT => $1,234,567,890.50