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)