Converting nested hash keys from CamelCase to snake_case in Ruby Converting nested hash keys from CamelCase to snake_case in Ruby ruby ruby

Converting nested hash keys from CamelCase to snake_case in Ruby


If you use Rails:

Example with hash: camelCase to snake_case:

hash = { camelCase: 'value1', changeMe: 'value2' }hash.transform_keys { |key| key.to_s.underscore }# => { "camel_case" => "value1", "change_me" => "value2" }

source:http://apidock.com/rails/v4.0.2/Hash/transform_keys

For nested attributes use deep_transform_keys instead of transform_keys, example:

hash = { camelCase: 'value1', changeMe: { hereToo: { andMe: 'thanks' } } }hash.deep_transform_keys { |key| key.to_s.underscore }# => {"camel_case"=>"value1", "change_me"=>{"here_too"=>{"and_me"=>"thanks"}}}

source: http://apidock.com/rails/v4.2.7/Hash/deep_transform_keys


You need to treat Array and Hash separately. And, if you're in Rails, you can use underscore instead of your homebrew to_snake_case. First a little helper to reduce the noise:

def underscore_key(k)  k.to_s.underscore.to_sym  # Or, if you're not in Rails:  # to_snake_case(k.to_s).to_symend

If your Hashes will have keys that aren't Symbols or Strings then you can modify underscore_key appropriately.

If you have an Array, then you just want to recursively apply convert_hash_keys to each element of the Array; if you have a Hash, you want to fix the keys with underscore_key and apply convert_hash_keys to each of the values; if you have something else then you want to pass it through untouched:

def convert_hash_keys(value)  case value    when Array      value.map { |v| convert_hash_keys(v) }      # or `value.map(&method(:convert_hash_keys))`    when Hash      Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] }]    else      value   endend


I use this short form:

hash.transform_keys(&:underscore)

And, as @Shanaka Kuruwita pointed out, to deeply transform all the nested hashes:

hash.deep_transform_keys(&:underscore)