【问题标题】:Symbols used as Hash keys get converted to Strings when serialized用作哈希键的符号在序列化时转换为字符串
【发布时间】:2011-03-20 18:49:04
【问题描述】:

当我将 Array 或 Hash 分配给 Mongo 文档的属性时,它会正确 序列化,但 Symbols 用作 Hash 键时除外。简单例子:

irb>MyMongoModel.create :some_attr => {:a => [:b,:c]} 
=> #<MyMongoModel _id: 4d861c34c865a1f06a000001, some_attr: {:a=>[:b, :c]}> 

irb>MyMongoModel.last 
=> #<MyMongoModel _id: 4d861c34c865a1f06a000001, some_attr: {"a"=>[:b, :c]}> 

请注意,some_attr 被检索为 {"a"=&gt;[:b, :c]},而不是 {:a=&gt;[:b, :c]}

嵌套哈希也会发生这种情况(例如,在数组或其他哈希内部)。有没有办法在这种情况下保留符号?

解决方案

我使用 YAML 在存储之前手动序列化 some_attr - YAML.dump(或 Object#to_yaml),并在读取属性后使用 YAML::load。 YAML 更好地保留了序列化对象。 ActiveRecord 正在使用 YAML 在ActiveRecord::Base 上实现其serialize 类方法。

【问题讨论】:

  • 什么 rails 和 ruby​​ 版本?我的 Rails 3.0.5 和 Ruby EE 运行良好
  • 感谢 YAML 提示。我正在使用带有符号键和任意对象作为值的键/值集合。使用 YAML 进行序列化非常适合。

标签: ruby-on-rails ruby mongodb mongoid


【解决方案1】:

这很可能与您用来为模型提供持久层的 ORM 有关。您可能可以使用以HashWithIndifferentAccess 形式返回它的方法包装some_attr,然后您可以使用字符串或数组访问它。由于您使用的是 Rails,因此可以通过在 Hash 对象上调用 with_indifferent_access 方法来激活此功能。 (如果你有一个 Hash 对象数组,你当然需要在每个对象上调用它)该方法将返回相同的哈希,但随后符号查找将起作用。

来自您的代码:

new_hash = MyMongoModel.last.some_attr.with_indifferent_access
new_hash[:a] # Will return the same as new_hash['a'] 

希望这会有所帮助!

【讨论】:

  • 这种方式的问题是事先不知道序列化对象的结构,hash可以嵌套在任意层级。但是,看起来,没有更好的方法,所以,我接受这个答案。谢谢!
  • 您可以编写一个简单的方法来检查和循环结构,根据需要转换哈希值。
【解决方案2】:

这里的罪魁祸首是 BSON 序列化。当你序列化一个用作哈希键的符号时,它实际上被翻译成一个字符串,当你要求它返回时,你得到的是字符串而不是符号。

我遇到了和你一样的问题,我正在考虑扩展 Hash 类以包含一种将所有“字符串”键转换为 :symbols 的方法。

不幸的是,我不在 Rails 上,所以我不能按照 ctcherry 的建议使用 with_indifferent_access

【讨论】:

  • 这实际上是 JSON 的一个“特性”(BSON 只是一种二进制编码)。所有键都必须是字符串。见json.org
  • 当然,我并没有把它当成一个错误,只是解释它为什么会发生......
  • 将字符串键转换为符号的问题是事先不知道序列化对象的结构,因此,哈希可以嵌套在任何级别。我决定改为使用手动序列化some_attr,使用 YAML.dump(写入前)和 YAML::load(读取后)。 YAML 按原样保留对象。 Rails 使用它在 ActiveRecord 中实现其“序列化”类方法。
【解决方案3】:

我不确定是否保留符号,但您可以将字符串转换回符号。

str.to_sym

【讨论】:

    【解决方案4】:

    找到这个,效果很好,并且您已将字段定义为 Hash:

    https://github.com/mindscratch/mongoid-indifferent-access

    【讨论】:

      猜你喜欢
      • 2012-09-11
      • 2020-10-31
      • 2012-12-12
      • 1970-01-01
      • 2011-05-19
      • 2016-07-30
      • 2017-01-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多