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

我有一张桌子 items 有一个列 price 类型的 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 ,这可能只是一种痛苦。

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

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

其他提示

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

你需要

  • 金钱宝石 (4.1.0版本)
  • 以模型为例 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) }
  # ...

你会得到什么:

  • 如果没有任何额外的更改,所有表格都将显示美元和美分,但内部表示仍然只是美分。这些表格将接受“$12,034.95”等值并为您进行转换。无需向模型添加额外的处理程序或属性,或在视图中添加帮助程序。
  • 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 

要理智 - 检查你的价值观。

使用 money-rails gem 。它可以很好地处理模型中的货币和货币,并且还有一堆帮助器来格式化您的价格。

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

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

使用虚拟属性(链接到修订(付费)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中为您提供纯粹的Float。

如果有人使用续集,迁移将类似于:

add_column :products, :price, "decimal(8,2)"
不知怎的,Sequel忽略了:精度和:比例

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

我正是以这种方式使用它:

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

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

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

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

Dylan Markow 发布

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

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

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

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

Ruby&amp;的简单代码轨道

<%= number_to_currency(1234567890.50) %>

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

对于一些有抱负的 RoR 开发初级者/初学者来说,这只是一个小小的更新和所有答案的凝聚力,他们肯定会来这里寻求一些解释。

用钱工作

使用 :decimal 正如 @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 将被用作 BigDecimal 这解决了很多问题。

  • precisionscale 应该根据您所代表的内容进行调整

    • 如果您从事接收和发送付款工作, precision: 8scale: 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}'

正如本中所解释的 博客 邮政。

货币格式

告别额外的库并使用内置帮助器。使用 number_to_currency 正如@molf 和@facundofarias 所建议的。

和玩 number_to_currency Rails 控制台中的助手,发送调用 ActiveSupportNumberHelper 类以便访问助手。

例如:

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

给出以下输出

2500000,61€

检查其他 options数字对货币 帮手。

放在哪里

您可以将其放入应用程序助手中,并在视图中使用任意数量的内容。

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

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

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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top