Rails的JSON序列化十进制添加行情

我使用默认的JSON序列化模型,它具有许多十进制和整数属性。 示例结果是:

{ "user": { "id": 1234, "rating": "98.7" } } 

注意围绕“评级”的值加引号。 这会导致我正在使用的反序列化库将它们错误地视为string(而不是小数)。 可以将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 

这已经改变了Rails 4.0,它有ActiveSupport.encode_big_decimal_as_string选项,所以你可以指定你的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抽出string存储为BigDecimal美元金额。

从语言A到语言B处理小数的唯一“安全”方法是使用string。 如果你的json包含"rating": 98.79999999999999它可能会被JavaScript运行时转换为98.79999999999998

请参阅BigDecimal as_json文档:

一个BigDecimal会自然地表示为一个JSON数字。 但是,大多数库直接将非整数JSON数字parsing为浮点数。 使用这些库的客户端通常会得到一个错误的号码,无法恢复,而不是手动检查JSON代码本身的string。

这就是为什么返回一个JSONstring。 JSON文字不是数字,但如果另一端通过合约知道数据应该是BigDecimal,它仍然有机会后处理string并获得实际值。

如果你想强制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 

如果您使用的是ActiveModel :: Serializer,则还可以使用to_f强制从“十进制”到“浮点”types的转换。 这也将削减你的报价!

所以在你的对象序列化类。 做

 def rating self.rating.to_f end 

使用Rails 5 encode_big_decimal_as_string不起作用(它已被弃用,所以不出意外)。

如果你添加jbuilder到你的应用程序

 # Gemfile gem 'jbuilder', '~> 2.5' 

然后,只需创build一个json视图,将小数转换为仅用于视图的浮点数,则应该是黄金。

 # app/views/yourmodel/index.json.jbuilder json.array! @yourmodels do |yourmodel| json.attributethatisadecimal yourmodel.attributethatisadecimal.to_f end 

这对我来说效果很好 – 多一点工作(因为你必须将你的模型映射到jbuilder),但是这种方法看起来很干净。