我在Ruby 1.8.7上使用Rails 3.2.1和Jbuilder构建一个简单的JSON API(1.9.x可能对我有所帮助,但我的托管服务提供商只有1.8.7)。
由于API使用者期望时间戳为浮点数,我现在只对时间属性做一个简单的to_f
:
json.updated_at record.updated_at.to_f #=> 1328242368.02242
但to_f
导致精确损失。当客户端请求自给定时间点以来已修改的记录时,这会导致一些问题,因为SQL查询找到客户端用于引用的相同记录。即当尝试查找比上面的示例更“新”的记录时,SQL查询(例如updated_at > Time.at(1328242368.02242)
)返回相同的记录,因为updated_at
的实际值比给定的时间戳更精确且更小。
实际上,record.updated_at.usec #=> 22425
或0.022425
秒。注意额外的小数。
因此,最佳地,时间戳应该是JSON,带有1个额外的小数,例如1328242368.022425,但我无法找到实现这一目标的方法。
updated_at.to_i #=> 1328242368 # seconds
updated_at.usec #=> 22425 # microseconds
updated_at.to_f #=> 1328242368.02242 # precision loss
# Hacking around `to_f` doesn't help
decimals = updated_at.usec / 1000000.0 #=> 0.022425 # yay, decimals!
updated_at.to_i + decimals #=> 1328242368.02242 # dammit!
我四处寻找设置默认浮点精度的方法,但我很难过。有什么想法吗?
编辑:我应该补充说API使用者没有运行JavaScript,所以float 可以具有更高的精度。它会破坏JS兼容性(因此JSON规范)添加另一个数字(十进制或其他),因为JS浮动无法处理,我相信。所以也许我需要一种完全不同的方法......
答案 0 :(得分:1)
在评论中进行审议之后,最佳选择似乎是monkeypatching ActiveSupport::JSON
以使其BigDecimal
与Numeric
s相同:
class BigDecimal
def as_json(options = nil) self end #:nodoc:
def encode_json(encoder) to_s end #:nodoc:
end
这会覆盖Rails团队决定在JSON解串器中防止序列化BigDecimal
被解析为浮点数(并且丢失精度)而不支持十进制数。