成千上万的Rails金额被截断

在我的Rails 5应用程序中,我读了一个产品的feed。 在JSON中,当价格超过1,000美元时,JSON有一个逗号,如1,000。

我的代码似乎是截断它,所以它存储为1而不是1,000。

所有其他字段都正确存储。 有人可以告诉我我做错了什么吗?

在此示例中,reg_price保存为2,而不是2590。

json示例(对于reg_price字段):

[ { "reg_price": "2,590" } ] 

模式

 create_table "products", force: :cascade do |t| t.decimal "reg_price", precision: 10, scale: 2 end 

模型

 response = open_url(url_string).to_s products = JSON.parse(response) products.each do |product| product = Product.new( reg_price: item['reg_price'] ) product.save end 

你没有做错任何事。 小数不适用于逗号分隔符。 我不确定有什么好方法可以修复这个问题。 但作为一个选项,您可以定义一个虚拟属性:

 def reg_price=(reg_price) self[:reg_price] = reg_price.gsub(',', '') end 

发生这种情况的原因与Rails无关。

  1. JSON是一个非常简单的文档结构,不支持数字分隔符。 JSON文档中的值是字符串。
  2. 当您收到String作为输入并且想要将其存储为Integer时,需要将其强制转换为适当的类型。
  3. Ruby已经内置了对此的支持,Rails正在使用它: "1".to_s #=> 1
  4. 特定的启发式Ruby用于将字符串转换为整数是将任何数字转换为非数字字符并将其转换为整数。 在Ruby中,逗号是非数字的,至少在默认情况下是非数字的。

解决方案是使用另一种方法将JSON中的字符串值转换为整数。 您可以通过以下任何方式执行此操作:

  1. 在将字符串发送到ActiveRecord模型之前将其转换为整数。
  2. 更改字符串的方式是默认的Ruby转换将字符串转换为期望值。
  3. 使用自定义脚轮来处理此特定属性的转换(在ActiveRecord和ActiveModel内部)。

@Danil提出的解决方案遵循上面的#2,它有一些缺点(正如@tadman指出的那样)。

处理这种问题的一种更强大的方法是使用像Delocalize这样的库,它将自动处理数字字符串解析和转换,同时考虑活动区域设置使用的分隔符。 有关更多信息,请参阅Benoit Garret的优秀答案 。