How to elegantly symbolize_keys for a 'nested' hash

SHS picture SHS · Jul 24, 2014 · Viewed 32.3k times · Source

Consider the following code:

  hash1 = {"one" => 1, "two" => 2, "three" => 3}
  hash2 = hash1.reduce({}){ |h, (k,v)| h.merge(k => hash1) }
  hash3 = hash2.reduce({}){ |h, (k,v)| h.merge(k => hash2) }
  hash4 = hash3.reduce({}){ |h, (k,v)| h.merge(k => hash3) }

hash4 is a 'nested' hash i.e. a hash with string keys and similarly 'nested' hash values.

The 'symbolize_keys' method for Hash in Rails lets us easily convert the string keys to symbols. But I'm looking for an elegant way to convert all keys (primary keys plus keys of all hashes within hash4) to symbols.

The point is to save myself from my (imo) ugly solution:

  class Hash
    def symbolize_keys_and_hash_values
      symbolize_keys.reduce({}) do |h, (k,v)|
        new_val = v.is_a?(Hash) ? v.symbolize_keys_and_hash_values : v
        h.merge({k => new_val})
      end
    end
  end

  hash4.symbolize_keys_and_hash_values #=> desired result

FYI: Setup is Rails 3.2.17 and Ruby 2.1.1

Update:

Answer is hash4.deep_symbolize_keys for Rails <= 5.0

Answer is JSON.parse(JSON[hash4], symbolize_names: true) for Rails > 5

Answer

jvnill picture jvnill · Jul 24, 2014

There are a few ways to do this

  1. There's a deep_symbolize_keys method in Rails

    hash.deep_symbolize_keys!

  2. As mentioned by @chrisgeeq, there is a deep_transform_keys method that's available from Rails 4.

    hash.deep_transform_keys(&:to_sym)

    There is also a bang ! version to replace the existing object.

  3. There is another method called with_indifferent_access. This allows you to access a hash with either a string or a symbol like how params are in the controller. This method doesn't have a bang counterpart.

    hash = hash.with_indifferent_access

  4. The last one is using JSON.parse. I personally don't like this because you're doing 2 transformations - hash to json then json to hash.

    JSON.parse(JSON[h], symbolize_names: true)

UPDATE:

16/01/19 - add more options and note deprecation of deep_symbolize_keys

19/04/12 - remove deprecated note. only the implementation used in the method is deprecated, not the method itself.