开发者

Symbols used as Hash keys get converted to Strings when serialized

When I assign an Array or Hash to an attribute of a Mongo document, it gets properly serialized except for Symbols when they are used as Hash keys. Simple example:

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]}> 

Please, note 开发者_运维技巧that some_attr is retrieved as {"a"=>[:b, :c]}, not as {:a=>[:b, :c]}

This also happens for nested Hashes (e.g., inside of Arrays or other Hashes). Is there a way to preserve Symbols in such cases?

Solution

I'm using YAML to manually serialize some_attr - YAML.dump (or Object#to_yaml) before storing, and YAML::load after reading the attribute. YAML preserves the serialized object better. ActiveRecord is using YAML to implement its serialize class method on ActiveRecord::Base.


More than likely this has to do with the ORM you are using to provide the persistance layer for the model. You can probably wrap some_attr with a method that returns it in the form of a HashWithIndifferentAccess which you can then access with either strings or arrays. Since you are using Rails, this functionality can be activated by calling the with_indifferent_access method on the Hash object. (If you have an array of Hash objects, you'll need to call it on each one of course) The method will return the same hash, but then symbol lookups will work.

From your code:

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

Hope this helps!


the culprit here is the BSON serialization. when you serialize a symbol used as a key for hashes, it is actually translated to a string and when you ask it back you get the string instead of the symbol.

i'm having the same problem as you and i'm thinking of extending the Hash class to include a method to convert all the "string" keys to :symbols.

unfortunately i'm not on Rails so i cannot use the with_indifferent_access as suggested by ctcherry.


I'm not sure about preserving symbols but you can convert the strings back to symbols.

str.to_sym


Found this, works well and you have define the field as Hash:

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜