This post originated from an RSS feed registered with Ruby Buzz
by Guy Naor.
Original Post: Beware of HashWithIndifferentAccess#symbolize_keys!
Feed Title: Famundo - The Dev Blog
Feed URL: http://devblog.famundo.com/xml/rss/feed.xml
Feed Description: A blog describing the development and related technologies involved in creating famundo.com - a family management sytem written using Ruby On Rails and postgres
While working on our Famundo application, we used the symbolize_keys! method of one of the Hashs in rails, not realizing it was actually a HashWithIndifferentAccess. To our amazement, all the entries in the hash just disappeared.
Not ones to leave alone an inexplicable event, we decided to research it a bit. Time to dig into the rails code for Hash. This is the code used to symbolize the keys (in keys.rb):
# Destructively convert all keys to symbols.
1 def symbolize_keys!
2 keys.each do |key|
3 unless key.is_a?(Symbol)
4 self[key.to_sym] = self[key]
5 delete(key)
6 end
7 end
8 self
9 end
The source of the problem is that in a HashWithIndifferentAccess a symbol and a string are treated as one and the same, by converting the symbol into a string on assignment to the hash. Line 3 will be true for every key in the hash entered as either a symbol (that was converted to a string) or a string. The assignment in line 4 will actually assign the value to itself, and then line 5 will delete our key, leaving us with an empty hash. The best way to see it is to launch script/console, and enter the following:
The fix is pretty simple and involves making sure that we don't try to run symbolize_keys! on a HashWithIndifferentAccess. So the new method will now be:
# Destructively convert all keys to symbols.
def symbolize_keys!
unless self.kind_of? HashWithIndifferentAccess # This is the added check
keys.each do |key|
unless key.is_a?(Symbol)
self[key.to_sym] = self[key]
delete(key)
end
end
end
self
end
I submitted a ticket with a patch to the Rails trac. I hope it'll be included soon so that nobody else get bitten by this bug.