我在我的项目中使用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!
但它不起作用。
重点是,如果我们手动在控制台中执行这些过程,则使用符号键保存散列!
任何想法?
答案 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票证并请求“查询应该返回一个具有无差异访问权限的哈希”。 它将帮助我们确定优先顺序。