为什么模型的哈希字段键没有保存为符号?

时间:2013-11-22 19:55:54

标签: ruby-on-rails ruby mongoid

我在我的项目中使用mongoid并且有一个具有哈希字段的模型:

field :settings, type: Hash

我定义了after_create回调以在模型创建后设置一些设置:

after_create :set_settings
def set_settings
settings[:test] = true
save!
end

但现在我看到散列是用字符串键保存的,而不是用符号键保存的:

 {"test"=>true}

然后我尝试symbolize_keys这样:

settings[:test] = true
settings.symbolize_keys!
save!

但它不起作用。

重点是,如果我们手动在控制台中执行这些过程,则使用符号键保存散列!

任何想法?

2 个答案:

答案 0 :(得分:1)

Rails使用类HashWithIndifferentAccess来允许使用字符串或符号访问Hash的密钥,而不管底层实现。我怀疑在幕后某处,你的哈希被转换为其中一个对象。

至于为什么键被保存为字符串,我怀疑是与symbols are not garbage collected这个事实有关,如果你不小心的话,可以利用这个事实来允许DOS攻击。

答案 1 :(得分:1)

在MongoDB中,Ruby Hash映射并序列化为BSON文档(或嵌入文档) 使用(e_name)键作为CStrings。参考:

http://bsonspec.org/#/specification

因此,密钥在序列化时被字符串化,将字符串键和符号键折叠在一起并失去区别。 在反序列化回到Ruby哈希时,当前驱动程序映射到字符串键。 在MongoDB,Inc。Ruby驱动程序(mongo gem,github mongo-ruby-driver)版本1.8中, 我们试图通过定义我们自己的HashWithIndifferentAccess ala Rails解决这个问题, 但内部符号而不是字符串。 但是我们遇到了JRuby的Java扩展并发症,并且不得不恢复该功能。参考:

https://jira.mongodb.org/browse/RUBY-434

在2.0版本中,我们计划使用新的bson-ruby https://github.com/mongodb/bson-ruby实现 它主要是Ruby,具有最小的C和Java扩展。 我们应该能够重新审视实施。

有一些性能方面的考虑因素。 目前,当生成新的String时,Symbol#to_s比预期的更昂贵。 看起来好像Ruby核心语言优化就是记住字符串。 因此,序列化符号键实际上比序列化字符串键更昂贵。

请随意打开一张新的Ruby票证并请求“查询应该返回一个具有无差异访问权限的哈希”。 它将帮助我们确定优先顺序。