Rails JSON序列化Decimal添加引号

Kev*_*tre 48 ruby-on-rails

我正在为具有多个十进制和整数属性的模型使用默认的JSON序列化.一个示例结果是:

{ "user": { "id": 1234, "rating": "98.7" } }
Run Code Online (Sandbox Code Playgroud)

请注意在"评级"值附近添加引号.这导致我正在使用的反序列化库错误地将它们视为字符串(而不是小数).可以将Rails设置为不使用所有小数的引号吗?

编辑:

如果这有所不同,我在Rails 3.0.7和Ruby 1.9.2上.

编辑:

终奌站:

rails g model user rating:decimal
rake db:migrate
Run Code Online (Sandbox Code Playgroud)

安慰:

user = User.create(rating: 98.7)
user.to_json
Run Code Online (Sandbox Code Playgroud)

Mar*_*rth 44

将小数字从A语言移到语言B的唯一"安全"方法是使用String.如果你的json包含"rating": 98.79999999999999它,它可能会98.79999999999998被你的JavaScript运行时转换.

请参阅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
Run Code Online (Sandbox Code Playgroud)


tox*_*xaq 28

对于具有选项的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
Run Code Online (Sandbox Code Playgroud)

这解决了我的问题,RABL抽出存储为BigDecimal的美元金额的字符串.

  • 不幸的是,在Rails 4.1中再次弃用了`encode_big_decimal_as_string`选项. (5认同)
  • 显然你可以使用`activesupport-json_encoder` gem来恢复它 (2认同)

ale*_*xzg 10

如果您使用的是ActiveModel :: Serializer,您还可以使用to_f强制从Decimal转换为Float类型.那也会为你剪掉报价!

所以在你的对象序列化器类中.做

def rating
  self.rating.to_f
end
Run Code Online (Sandbox Code Playgroud)

  • 这会导致"SystemStackError(堆栈级别太深)"异常.使用object.rating.to_f工作正常. (4认同)
  • 但这不会完全破坏使用BigDecimal的重点吗?例如,如果我试图将货币值传递给API端点,这种方法将重新引入Floats固有的所有舍入误差.如果它破坏数据,则不应将其视为解决方案. (3认同)