Jocellyn's Blog

Hash with indifferent access

Hash with indifferent access is the actual class of Rails params, so technically speaking it is not just a hash, as I wrote :) The “indifferent access” sounds scary but I am sure you all know what it means. When you want to get a value based on a key, the key can be written as string as well as symbol.

# We will set our new hash with i.a. with one key/value pair
dogs = ActiveSupport::HashWithIndifferentAccess.new
dogs[:husky] = "Matt"

# we can get the value by both, string and symbol
dogs[:husky] # => "Matt"
dogs['husky'] # => "Matt"

The string and the symbol is treated as a same thing. If you want to explicitely convert all the keys to one or other, you can use stringify_keys or symbolize_keys method. Anyway, if we create a hash with symbol keys, it will be converted to string internally.

symbol_hash = ActiveSupport::HashWithIndifferentAccess.new
symbol_hash[:foo] = "bar"

symbol_hash # => {"foo" => "bar" }

This is because the []= method is converting keys and values for string every time it is used. Look at the implementation of that method in Rails:

def []=(key, value)
  regular_writer(convert_key(key), convert_value(value, for::assignment))
end

def convert_key(key)
  key.kind_of?(Symbol) ? key.to_s : key
end

You should be aware of using regular hashes and hashes with indifferent access as putting these two together may end up unexpectedly. If you merge them together and they contain the same keys, you will end up by having both, not just the later ones.

regular = Hash.new
regular[:one] = 1
regular[:two] = 2

regular # => {:one=>1, :two=>2}

indifferent = HashWithIndifferentAccess.new
indifferent[:one] = "one"

regular.merge(indifferent) # => {:one=>1, :two=>2, "one"=>"one",
"two"=>"two"}

Hovewer, if you do it the opposite way (merging regular into indifferent) it will do what is expected and we will have the later values: {"one" => 1, "two" => 2} but it will become also an indifferent hash, so the keys wil be stringified.

P.S. if you want to play with these example in your console, do not forget to include the hash with indifferent acces like this:

require "active_support/hash_with_indifferent_access"


Comments

comments powered by Disqus