使用Oj.dump进行序列化时,将符号转换为字符串

时间:2014-01-09 19:17:23

标签: ruby-on-rails ruby json serialization hash

问题摘要:我正在尝试使用Oj gem将哈希序列化为JSON。似乎Oj不会自动将哈希的符号键转换为字符串。我想知道Oj是否有序列化期间“字符串化”的选项?

这是我的哈希的一个例子:

example_hash = 
 {:id=>1234,
  :asset_number=>"1234-5678",
  :latitude=>34.78495,
  :longitude=>-92.12899,
  :last_tracking_record_id=>123456789,
  :bearing=>42,
  :threat_level=>:severe}

上面的内容如下:

render json: Oj.dump(example_hash)

遗憾的是,生成的JSON具有与上面完全相同的键,这意味着我需要像JavaScript一样访问JavaScript中的元素:response[:asset_number]。由于客户端代码是在几个月前实现的,并且现在只添加了Oj,我更愿意找到一种在序列化服务器端串行化密钥的方法。

Oj有一个名为symbol_keys的选项,它是一个布尔值,但是将其设置为truefalse似乎在这方面没有效果。

我到目前为止找到的唯一解决方案是使用this answer中建议的with_indifferent_access,但在某些情况下,我有哈希数组;虽然我可以在技术上为该数组中的每个哈希调用该方法,但是考虑到Oj旨在加速Json序列化,我宁愿找到一种方法来使用Oj本身。最后,我想知道在Oj中是否有一个选项或设置将在序列化期间执行此

2 个答案:

答案 0 :(得分:11)

在我写这个问题时,我找到了答案。由于我在StackOverflow上找不到与此问题相关的任何其他答案(特别是关于Oj gem),我将保留这篇文章,希望它能帮助我处理其他人。

根据this previously discussed issue on GitHub,将选项mode设置为:compat确实会将符号转换为字符串。所以我的渲染线现在看起来像这样:

render json: Oj.dump(example_hash, mode: :compat)

根据Oj documentation for default_options:compat模式定义如下:

  

...与其他系统兼容。它将序列化任何对象,但会   检查Object是否实现了to_hash()或to_json()方法。   如果存在,则该方法用于序列化Object。该   to_hash()更灵活,产生更一致的输出   优先于to_json()方法。如果没有to_json()   或者to_hash()方法然后存在Oj内部Object变量   使用编码。

因此,如果我正确地解释这一点,似乎此解决方案可行,因为它最终使用to_json类的Hash方法。

我不确定我是否影响了性能(无论是积极的还是消极的),但至少它使我不必在阵列的情况下手动调用with_indifferent_accessto_json

<强>更新

关于效果,cmwright做了一些基准测试,并得出了这些结果:

Rehearsal ----------------------------------------------
json        13.990000   0.250000  14.240000 ( 14.257051)
oj default   3.260000   0.230000   3.490000 (  3.491028)
oj compat    3.360000   0.240000   3.600000 (  3.593109)
------------------------------------ total: 21.330000sec

                 user     system      total        real
json        13.740000   0.240000  13.980000 ( 13.992641)
oj default   3.020000   0.230000   3.250000 (  3.248077)
oj compat    3.060000   0.230000   3.290000 (  3.286443)

似乎compat选项至少与默认的Oj选项相同,而且效率明显高于普通'to_json

这是包含基准代码的gist

答案 1 :(得分:1)

使用generate方法可以提供相同的输出。

Oj.generate({a: `test`})