Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Adding deep versions of stringify_keys and symbolize_keys (plain and bang) for nested hashes #6060

Merged
merged 1 commit into from

10 participants

@lucashungaro

I have to carry around some snippets 'cause I always use these methods (specially deep_symbolize_keys) when I use YAML files with custom app configuration. Some people I know also have their own versions, so I thought adding them to ActiveSupport was a good idea.

activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -51,4 +51,56 @@ def assert_valid_keys(*valid_keys)
raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
end
end
+
+ # Return a new hash with all keys converted to strings.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_stringify_keys
+ result = {}
+ self.each do |key, value|
+ if value.is_a?(Hash)
+ result[(key.to_s)] = value.deep_stringify_keys
@josevalim Owner

Can we remove the parenthesis here in the hash access pls?

Woops! My bad. Doing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
activesupport/lib/active_support/core_ext/hash/keys.rb
((12 lines not shown))
+ result[(key.to_s)] = value.deep_stringify_keys
+ else
+ result[(key.to_s)] = self[key]
+ end
+ end
+ result
+ end
+
+ # Destructively convert all keys to strings.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_stringify_keys!
+ keys.each do |key|
+ self[key.to_s] = delete(key)
+ end
+ values.each{ |h| h.deep_stringify_keys! if h.is_a?(Hash) }
@josevalim Owner

Can we loop keys and values once?

I think so. I did them separately to ease the understanding of what's going on, but it would be easy to do in one step.

Ok, after further review, I can't change the own hash inside an each block (it throws an exception). I could copy the hash and do the conversions, then change self to reference the new hash or just keep iterating over keys and values separately. What do you think?

@gazay
gazay added a note

Yes, I think it can be done similar to this #5939

Using each_with_object?

@gazay
gazay added a note

Yes, sorry, I was from phone, can't write more

Something like this:

each_with_object({}) do |(key, value), hash|
  hash[key.to_s] = value.is_a?(Hash) ? value.deep_stringify_keys! : value
end

It's the same as you described

This would make a copy, right? If a use each_with_object(self) I'll have the same problem (modifying the object while iterating over it). I think I'm missing something...

@gazay
gazay added a note

Oh, I was wrong, sorry. My example will works fine with non-destructive version of this method https://github.com/rails/rails/pull/6060/files#L0R58. In ruby you can't change value of self, so you need to do something like this:

def deep_stringify_keys!
  stringified = deep_stringify_keys
  self.clear.merge! stringified
end

Yeah, that was what I thought at first. I'll think about a way to benchmark this and see which version is faster. Thanks!

Also, I'm repeating the logic in every method instead of reusing it (like in your example) because sometimes people will undef some of these methods. I found one case while writing this code, so I decided to just repeat the key conversion code in every method. Maybe extracting that part to a private method and reusing it would be fine.

@gazay
gazay added a note

By my benchmark test separate iteration is faster than my example about 1.5 times :)

I've found similar results. The code that iterates over keys and then values takes ~6.4s to do deep_stringify_keys! 1 million times. The code that loops over keys and values at once copying the array and "rebuilding" self after takes ~8.9s.

So, I think I'll leave the code as it is now. Anything else I can improve upon?

@gazay
gazay added a note

I found better solution and only with one iteration:

def deep_stringify_keys!
  keys.each do |key|
    val = delete(key)
    self[key.to_s] = val.is_a?(Hash) ? val.deep_stringify_keys! : val
  end
  self
end

It faster then separate iteration

Nice @gazay! It seems Ruby doesn't mind if you change the hash while iterating over the keys only. Good to know. :)

I made a commit using this code for deep_stringify_keys! and deep_symbolize_keys!.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rafaelfranca

Related with #5587

@rafaelfranca

Related with #5724

activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -51,4 +51,56 @@ def assert_valid_keys(*valid_keys)
raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
end
end
+
+ # Return a new hash with all keys converted to strings.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_stringify_keys
+ result = {}
+ self.each do |key, value|
@gazay
gazay added a note

Self is unnecessary here

Sure. It's more a style thing. Should I remove it?

@rafaelfranca Owner

Yes please. We had a pull requesting from @gazay merged yesterday only changing these style things on Active Support

Ok, no problem. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -51,4 +51,48 @@ def assert_valid_keys(*valid_keys)
raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
end
end
+
+ # Return a new hash with all keys converted to strings.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_stringify_keys
+ result = {}
+ each do |key, value|
+ result[key.to_s] = value.is_a?(Hash) ? value.deep_stringify_keys : self[key]
@gazay
gazay added a note

Instead of calling [] on self will be better to pass just value in the false part of ternary operator

Yeah, way better. Missed that somehow. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Najaf

Quick heads up, may or not be relevant but i18n appears to implement deep_symbolize_keys in their core_ext/hash.rb too.

Also, minor annoyance (to which I'd be willing to put together a pull-request for). It would be nice if all hashes in arrays were deep symbolized too.

@lucashungaro

Najaf, I've saw i18n's code and it only defines the method if it isn't already defined. I tried to implement it in a way that doesn't break i18n.

My initial implementation took into account hashes inside arrays but then I thought that could be a bad surprise for some people and ignored that possibility. Should we have it?

@Najaf

+1 from me, I found it to be a bad surprise when it didn't symbolize hashes inside arrays.

@masterkain

+1 with backport

@carlosantoniodasilva

Hey @lucashungaro, thanks for your pull request. Perhaps you could add an entry to the changelog talking about the new methods, and some quick docs to AS Core Extensions guide before it goes in? Thanks!

@lucashungaro

Will do! :)

@lucashungaro

Ok, done. I added simple notes to the Guides mentioning the existence of the deep versions. Do you guys think this is enough or should I add "sections" dedicated to those?

Also, should I change the code to also convert keys from hashes inside arrays?

activesupport/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Adds `Hash#deep_symbolize_keys` and `Hash#deep_symbolize_keys!` to convert all keys from a +Hash+ instance into symbols *Lucas Húngaro*

I think you can comment about both deep_symbolize_keys and deep_stringify_keys :)

Gee, I need to rest. :P

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva

@lucashungaro not sure it's necessary to add a specific section for them... is it, @vijaydev? Thanks.

@vijaydev
Collaborator

@lucashungaro @carlosantoniodasilva No need for a specific section. I think what's in this PR is good enough. Add an example may be?

@lucashungaro

Ok, one more commit adding the changelog note and simple examples to the Guides. :)

@vijaydev
Collaborator

Squash the commits into one please.

@carlosantoniodasilva

@lucashungaro I believe it's fine to merge, but somehow it does not apply cleanly anymore (probably just the changelog conflicting). Can you rebase from current master? Thanks.

@carlosantoniodasilva

Thanks! But I guess I'll have to bother you again :P

Apparently this merge c1487f6 has messed up with your pull request, and it can't be merged again :D

@rafaelfranca

ooops! Sorry @lucashungaro.

@lucashungaro

@carlosantoniodasilva @rafaelfranca Shit happens ;). Did the rebase again.

@carlosantoniodasilva

@lucashungaro hehe, all the time :D.. Merging, thank you.

@carlosantoniodasilva carlosantoniodasilva merged commit 541429f into from
@rilian rilian commented on the diff
activesupport/lib/active_support/core_ext/hash/keys.rb
((18 lines not shown))
+ # nested hashes.
+ def deep_stringify_keys!
+ keys.each do |key|
+ val = delete(key)
+ self[key.to_s] = val.is_a?(Hash) ? val.deep_stringify_keys! : val
+ end
+ self
+ end
+
+ # Destructively convert all keys to symbols, as long as they respond
+ # to +to_sym+. This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_symbolize_keys!
+ keys.each do |key|
+ val = delete(key)
+ self[(key.to_sym rescue key)] = val.is_a?(Hash) ? val.deep_stringify_keys! : val
@rilian
rilian added a note

why stringify here ?

Silly mistake. It's correct on master, which uses a much improved code through transform_keys :)

@rilian
rilian added a note

huh, thanks :)

should I backport to activesupport the deep_transform_keys method that goes each Array value and transforms it for such hashes

{ :a => { :b => { :c => 3, :d => [ { :e => 4 }, { :f => 5 } ] } } }

useful for validation of hashes of model with has_many related models parsed from JSON

I think that would be nice. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rmsy

Sorry for the bump, but I just want to profess my sincere thanks for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 23, 2012
  1. @lucashungaro
This page is out of date. Refresh to see the latest.
View
6 activesupport/CHANGELOG.md
@@ -2,12 +2,16 @@
* Add `Hash#transform_keys` and `Hash#transform_keys!`. *Mark McSpadden*
-* Changed xml type `datetime` to `dateTime` (with upper case letter `T`). *Angelo Capilleri*
+* Changed xml type `datetime` to `dateTime` (with upper case letter `T`). *Angelo Capilleri*
* Add `:instance_accessor` option for `class_attribute`. *Alexey Vakhov*
* `constantize` now looks in the ancestor chain. *Marc-Andre Lafortune & Andrew White*
+* Adds `Hash#deep_stringify_keys` and `Hash#deep_stringify_keys!` to convert all keys from a +Hash+ instance into strings *Lucas Húngaro*
+
+* Adds `Hash#deep_symbolize_keys` and `Hash#deep_symbolize_keys!` to convert all keys from a +Hash+ instance into symbols *Lucas Húngaro*
+
* `Object#try` can't call private methods. *Vasiliy Ermolovich*
* `AS::Callbacks#run_callbacks` remove `key` argument. *Francesco Rodriguez*
View
44 activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -64,4 +64,48 @@ def assert_valid_keys(*valid_keys)
raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
end
end
+
+ # Return a new hash with all keys converted to strings.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_stringify_keys
+ result = {}
+ each do |key, value|
+ result[key.to_s] = value.is_a?(Hash) ? value.deep_stringify_keys : value
+ end
+ result
+ end
+
+ # Destructively convert all keys to strings.
+ # This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_stringify_keys!
+ keys.each do |key|
+ val = delete(key)
+ self[key.to_s] = val.is_a?(Hash) ? val.deep_stringify_keys! : val
+ end
+ self
+ end
+
+ # Destructively convert all keys to symbols, as long as they respond
+ # to +to_sym+. This includes the keys from the root hash and from all
+ # nested hashes.
+ def deep_symbolize_keys!
+ keys.each do |key|
+ val = delete(key)
+ self[(key.to_sym rescue key)] = val.is_a?(Hash) ? val.deep_stringify_keys! : val
@rilian
rilian added a note

why stringify here ?

Silly mistake. It's correct on master, which uses a much improved code through transform_keys :)

@rilian
rilian added a note

huh, thanks :)

should I backport to activesupport the deep_transform_keys method that goes each Array value and transforms it for such hashes

{ :a => { :b => { :c => 3, :d => [ { :e => 4 }, { :f => 5 } ] } } }

useful for validation of hashes of model with has_many related models parsed from JSON

I think that would be nice. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ end
+ self
+ end
+
+ # Return a new hash with all keys converted to symbols, as long as
+ # they respond to +to_sym+. This includes the keys from the root hash
+ # and from all nested hashes.
+ def deep_symbolize_keys
+ result = {}
+ each do |key, value|
+ result[(key.to_sym rescue key)] = value.is_a?(Hash) ? value.deep_symbolize_keys : value
+ end
+ result
+ end
end
View
4 activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -141,9 +141,13 @@ def delete(key)
end
def stringify_keys!; self end
+ def deep_stringify_keys!; self end
def stringify_keys; dup end
+ def deep_stringify_keys; dup end
undef :symbolize_keys!
+ undef :deep_symbolize_keys!
def symbolize_keys; to_hash.symbolize_keys end
+ def deep_symbolize_keys; to_hash.deep_symbolize_keys end
def to_options!; self end
# Convert to a Hash with String keys.
View
92 activesupport/test/core_ext/hash_ext_test.rb
@@ -24,11 +24,16 @@ def nested_under_indifferent_access
def setup
@strings = { 'a' => 1, 'b' => 2 }
+ @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } }
@symbols = { :a => 1, :b => 2 }
+ @nested_symbols = { :a => { :b => { :c => 3 } } }
@mixed = { :a => 1, 'b' => 2 }
+ @nested_mixed = { 'a' => { :b => { 'c' => 3 } } }
@fixnums = { 0 => 1, 1 => 2 }
+ @nested_fixnums = { 0 => { 1 => { 2 => 3} } }
@illegal_symbols = { [] => 3 }
@upcase_strings = { 'A' => 1, 'B' => 2 }
+ @nested_illegal_symbols = { [] => { [] => 3} }
end
def test_methods
@@ -37,8 +42,12 @@ def test_methods
assert_respond_to h, :transform_keys!
assert_respond_to h, :symbolize_keys
assert_respond_to h, :symbolize_keys!
+ assert_respond_to h, :deep_symbolize_keys
+ assert_respond_to h, :deep_symbolize_keys!
assert_respond_to h, :stringify_keys
assert_respond_to h, :stringify_keys!
+ assert_respond_to h, :deep_stringify_keys
+ assert_respond_to h, :deep_stringify_keys!
assert_respond_to h, :to_options
assert_respond_to h, :to_options!
end
@@ -61,34 +70,68 @@ def test_symbolize_keys
assert_equal @symbols, @mixed.symbolize_keys
end
+ def test_deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_symbols.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_strings.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_mixed.deep_symbolize_keys
+ end
+
def test_symbolize_keys!
assert_equal @symbols, @symbols.dup.symbolize_keys!
assert_equal @symbols, @strings.dup.symbolize_keys!
assert_equal @symbols, @mixed.dup.symbolize_keys!
end
+ def test_deep_symbolize_keys!
+ assert_equal @nested_symbols, @nested_symbols.dup.deep_symbolize_keys!
+ assert_equal @nested_symbols, @nested_strings.dup.deep_symbolize_keys!
+ assert_equal @nested_symbols, @nested_mixed.dup.deep_symbolize_keys!
+ end
+
def test_symbolize_keys_preserves_keys_that_cant_be_symbolized
assert_equal @illegal_symbols, @illegal_symbols.symbolize_keys
assert_equal @illegal_symbols, @illegal_symbols.dup.symbolize_keys!
end
+ def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized
+ assert_equal @nested_illegal_symbols, @nested_illegal_symbols.deep_symbolize_keys
+ assert_equal @nested_illegal_symbols, @nested_illegal_symbols.dup.deep_symbolize_keys!
+ end
+
def test_symbolize_keys_preserves_fixnum_keys
assert_equal @fixnums, @fixnums.symbolize_keys
assert_equal @fixnums, @fixnums.dup.symbolize_keys!
end
+ def test_deep_symbolize_keys_preserves_fixnum_keys
+ assert_equal @nested_fixnums, @nested_fixnums.deep_symbolize_keys
+ assert_equal @nested_fixnums, @nested_fixnums.dup.deep_symbolize_keys!
+ end
+
def test_stringify_keys
assert_equal @strings, @symbols.stringify_keys
assert_equal @strings, @strings.stringify_keys
assert_equal @strings, @mixed.stringify_keys
end
+ def test_deep_stringify_keys
+ assert_equal @nested_strings, @nested_symbols.deep_stringify_keys
+ assert_equal @nested_strings, @nested_strings.deep_stringify_keys
+ assert_equal @nested_strings, @nested_mixed.deep_stringify_keys
+ end
+
def test_stringify_keys!
assert_equal @strings, @symbols.dup.stringify_keys!
assert_equal @strings, @strings.dup.stringify_keys!
assert_equal @strings, @mixed.dup.stringify_keys!
end
+ def test_deep_stringify_keys!
+ assert_equal @nested_strings, @nested_symbols.dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_strings.dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_mixed.dup.deep_stringify_keys!
+ end
+
def test_symbolize_keys_for_hash_with_indifferent_access
assert_instance_of Hash, @symbols.with_indifferent_access.symbolize_keys
assert_equal @symbols, @symbols.with_indifferent_access.symbolize_keys
@@ -96,22 +139,46 @@ def test_symbolize_keys_for_hash_with_indifferent_access
assert_equal @symbols, @mixed.with_indifferent_access.symbolize_keys
end
+ def test_deep_symbolize_keys_for_hash_with_indifferent_access
+ assert_instance_of Hash, @nested_symbols.with_indifferent_access.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_symbols.with_indifferent_access.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_strings.with_indifferent_access.deep_symbolize_keys
+ assert_equal @nested_symbols, @nested_mixed.with_indifferent_access.deep_symbolize_keys
+ end
+
+
def test_symbolize_keys_bang_for_hash_with_indifferent_access
assert_raise(NoMethodError) { @symbols.with_indifferent_access.dup.symbolize_keys! }
assert_raise(NoMethodError) { @strings.with_indifferent_access.dup.symbolize_keys! }
assert_raise(NoMethodError) { @mixed.with_indifferent_access.dup.symbolize_keys! }
end
+ def test_deep_symbolize_keys_bang_for_hash_with_indifferent_access
+ assert_raise(NoMethodError) { @nested_symbols.with_indifferent_access.dup.deep_symbolize_keys! }
+ assert_raise(NoMethodError) { @nested_strings.with_indifferent_access.dup.deep_symbolize_keys! }
+ assert_raise(NoMethodError) { @nested_mixed.with_indifferent_access.dup.deep_symbolize_keys! }
+ end
+
def test_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access
assert_equal @illegal_symbols, @illegal_symbols.with_indifferent_access.symbolize_keys
assert_raise(NoMethodError) { @illegal_symbols.with_indifferent_access.dup.symbolize_keys! }
end
+ def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access
+ assert_equal @nested_illegal_symbols, @nested_illegal_symbols.with_indifferent_access.deep_symbolize_keys
+ assert_raise(NoMethodError) { @nested_illegal_symbols.with_indifferent_access.dup.deep_symbolize_keys! }
+ end
+
def test_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access
assert_equal @fixnums, @fixnums.with_indifferent_access.symbolize_keys
assert_raise(NoMethodError) { @fixnums.with_indifferent_access.dup.symbolize_keys! }
end
+ def test_deep_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access
+ assert_equal @nested_fixnums, @nested_fixnums.with_indifferent_access.deep_symbolize_keys
+ assert_raise(NoMethodError) { @nested_fixnums.with_indifferent_access.dup.deep_symbolize_keys! }
+ end
+
def test_stringify_keys_for_hash_with_indifferent_access
assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.stringify_keys
assert_equal @strings, @symbols.with_indifferent_access.stringify_keys
@@ -119,6 +186,13 @@ def test_stringify_keys_for_hash_with_indifferent_access
assert_equal @strings, @mixed.with_indifferent_access.stringify_keys
end
+ def test_deep_stringify_keys_for_hash_with_indifferent_access
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, @nested_symbols.with_indifferent_access.deep_stringify_keys
+ assert_equal @nested_strings, @nested_symbols.with_indifferent_access.deep_stringify_keys
+ assert_equal @nested_strings, @nested_strings.with_indifferent_access.deep_stringify_keys
+ assert_equal @nested_strings, @nested_mixed.with_indifferent_access.deep_stringify_keys
+ end
+
def test_stringify_keys_bang_for_hash_with_indifferent_access
assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.dup.stringify_keys!
assert_equal @strings, @symbols.with_indifferent_access.dup.stringify_keys!
@@ -126,6 +200,13 @@ def test_stringify_keys_bang_for_hash_with_indifferent_access
assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys!
end
+ def test_deep_stringify_keys_bang_for_hash_with_indifferent_access
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, @nested_symbols.with_indifferent_access.dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_symbols.with_indifferent_access.dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_strings.with_indifferent_access.dup.deep_stringify_keys!
+ assert_equal @nested_strings, @nested_mixed.with_indifferent_access.dup.deep_stringify_keys!
+ end
+
def test_nested_under_indifferent_access
foo = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
assert_kind_of ActiveSupport::HashWithIndifferentAccess, foo["foo"]
@@ -312,6 +393,17 @@ def test_stringify_and_symbolize_keys_on_indifferent_preserves_hash
assert_equal 1, h[:first]
end
+ def test_deep_stringify_and_deep_symbolize_keys_on_indifferent_preserves_hash
+ h = HashWithIndifferentAccess.new
+ h[:first] = 1
+ h = h.deep_stringify_keys
+ assert_equal 1, h['first']
+ h = HashWithIndifferentAccess.new
+ h['first'] = 1
+ h = h.deep_symbolize_keys
+ assert_equal 1, h[:first]
+ end
+
def test_to_options_on_indifferent_preserves_hash
h = HashWithIndifferentAccess.new
h['first'] = 1
View
14 guides/source/active_support_core_extensions.textile
@@ -2611,6 +2611,13 @@ The second line can safely access the "type" key, and let the user to pass eithe
There's also the bang variant +stringify_keys!+ that stringifies keys in the very receiver.
+Besides that, one can use +deep_stringify_keys+ and +deep_stringify_keys!+ to stringify all the keys in the given hash and all the hashes nested into it. An example of the result is:
+
+<ruby>
+{nil => nil, 1 => 1, :nested => {:a => 3, 5 => 5}}.deep_stringify_keys
+# => {""=>nil, "1"=>1, "nested"=>{"a"=>3, "5"=>5}}
+</ruby>
+
NOTE: Defined in +active_support/core_ext/hash/keys.rb+.
h5. +symbolize_keys+ and +symbolize_keys!+
@@ -2645,6 +2652,13 @@ The second line can safely access the +:params+ key, and let the user to pass ei
There's also the bang variant +symbolize_keys!+ that symbolizes keys in the very receiver.
+Besides that, one can use +deep_symbolize_keys+ and +deep_symbolize_keys!+ to symbolize all the keys in the given hash and all the hashes nested into it. An example of the result is:
+
+<ruby>
+{nil => nil, 1 => 1, "nested" => {"a" => 3, 5 => 5}}.deep_symbolize_keys
+# => {nil=>nil, 1=>1, :nested=>{:a=>3, 5=>5}}
+</ruby>
+
NOTE: Defined in +active_support/core_ext/hash/keys.rb+.
h5. +to_options+ and +to_options!+
Something went wrong with that request. Please try again.