How to elegantly symbolize_keys for a 'nested' hash How to elegantly symbolize_keys for a 'nested' hash ruby ruby

How to elegantly symbolize_keys for a 'nested' hash


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.


You cannot use this method for params or any other instance of ActionController::Parameters any more, because deep_symbolize_keys method is deprecated in Rails 5.0+ due to security reasons and will be removed in Rails 5.1+ as ActionController::Parameters no longerinherits from Hash

So this approach by @Uri Agassi seems to be the universal one.

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

However, Rails Hash object still does have it.

So options are:

  • if you don't use Rails or just don't care:

    JSON.parse(JSON[h], symbolize_names: true)
  • with Rails and ActionController::Parameters:

    params.to_unsafe_h.deep_symbolize_keys
  • with Rails and plain Hash

    h.deep_symbolize_keys


In rails you can create HashWithIndifferentAccess class. Create an instance of this class passing your hash to its constructor and then access it with keys that are symbols or strings (like params of Controller's Actions):

hash = {'a' => {'b' => [{c: 3}]}}hash = hash.with_indifferent_access# equal to:# hash = ActiveSupport::HashWithIndifferentAccess.new(hash)hash[:a][:b][0][:c]=> 3