问题描述
|
我正在为具有许多十进制和整数属性的模型使用默认的JSON序列化。一个示例结果是:
{ \"user\": { \"id\": 1234,\"rating\": \"98.7\" } }
请注意,在\“ rating \”值附近添加了引号。这会导致我正在使用的反序列化库将它们错误地视为字符串(而不是小数)。可以将Rails设置为不对所有小数使用引号吗?
编辑:
如果可以,那么我使用的是Rails 3.0.7和Ruby 1.9.2。
编辑:
终奌站:
rails g model user rating:decimal
rake db:migrate
安慰:
user = User.create(rating: 98.7)
user.to_json
解决方法
将小数从语言A传递到语言B的唯一“安全”方法是使用字符串。如果您的json包含
\"rating\": 98.79999999999999
,则JavaScript运行时可能会将其转换为98.79999999999998
。
请参阅BigDecimal as_json文档:
BigDecimal自然是
表示为JSON编号。最
库,但是,解析非整数
JSON数字直接作为浮点数。
使用这些库的客户会
通常得到一个错误的数字,没有
除了手动恢复的方法
使用JSON检查字符串
代码本身。
这就是为什么要返回JSON字符串的原因。
JSON文字不是数字,而是
如果对方知道合同规定
该数据应该是
BigDecimal,它仍然有机会
后处理字符串并获取
实际价值。
如果您想强制Rails不要引用它们,可以用猴子补丁BigDecimal(请参见Rails源代码)。
# not needed: to compare with the Numeric implementation
class Numeric
def as_json(options = nil) self end #:nodoc:
def encode_json(encoder) to_s end #:nodoc:
end
class BigDecimal
def as_json(options = nil) self end
def encode_json(encoder) to_s end #:nodoc:
end
,Rails 4.0的选项已更改为ѭ6,因此您可以指定BigDecimal序列化首选项。见问题6033
同时,如果您对6033年提出的参数感到满意,并且运行的Rails版本低于4.0,则可以通过猴子猴子BigDecimal进行如下修补
require \'bigdecimal\'
class BigDecimal
def as_json(options = nil) #:nodoc:
if finite?
self
else
NilClass::AS_JSON
end
end
end
这解决了RABL为存储为BigDecimal的美元金额抽出字符串的问题。
,如果使用ActiveModel :: Serializer,则还可以使用to_f强制从Decimal转换为Float类型。这也将为您节省报价!
所以在您的对象序列化器类中。做
def rating
self.rating.to_f
end
,使用Rails 5时,encode_big_decimal_as_string不起作用(已弃用,因此在此不会感到惊讶)。
如果将jbuilder添加到您的应用程序
# Gemfile
gem \'jbuilder\',\'~> 2.5\'
然后只需创建一个json视图,将小数转换为仅用于该视图的float即可,您应该是黄金的。
# app/views/yourmodel/index.json.jbuilder
json.array! @yourmodels do |yourmodel|
json.attributethatisadecimal yourmodel.attributethatisadecimal.to_f
end
这对我来说效果很好-要做更多的工作(因为您必须将模型映射到jbuilder),但是这种方法看起来很干净。