# Accessing Nested Hashes Directly

**URL:** <https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096>\
**Category:** Ruby\
**Created:** [September 26, 2006, 7:57pm UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096 "2006-09-26T19:57:47Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![toro04](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ea5d25/32.png) [@toro04](https://www.ruby-forum.com/u/toro04)\
**Post date:** [September 26, 2006, 7:57pm UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096/1 "2006-09-26T19:57:47Z")

</div>

I’ve been having a problem for a while with Ruby where accessing a hash  
within a hash will fail if the first hash is nil. As an example, Rails  
accepts XML input to an action by passing it through REXML. On an XML  
document like this:

 Tony Robbins 

You will receive a hash that looks like this (within the params hash):

“body” =\> { “user” =\> { “name” =\> { “given” =\> “Tony”, “family” =\>  
“Robbins” } } }

Thus, you can access the elements like this:

params[“body”][“user”][“name”][“given”]

However, sometimes the “name” element might not come over the wire  
(through no fault of Ruby’s nor Rails’ – it’s just a problem we have  
to deal with in our system). In this case, Ruby will throw a  
NoMethodError on nil.[] because we tried to access the value at “given”  
on an element that does not exist. Furthermore, sometimes the “user”  
element does not exist, either! This led me to code that looks like  
this:

if params[“body”][“user”]  
if params[“body”][“user”][“name”]  
first\_name = params[“body”][“user”][“name”][“given”]  
end  
end

That’s not very elegant when you’re doing it with many (15 - 30)  
fields. I also tried doing it with exceptions:

begin  
first\_name = params[“body”][“user”][“name”][“given”]  
rescue NoMethodError  
end

Also, not very elegant.

Finally, I wrote a method to work around this problem:

def get\_value(object, \*path)  
new\_object = object

```
for item in path
  item = item.to_s

  if new_object
    if new_object[item]
      new_object = new_object[item]
    else
      new_object = nil
    end
  else
    break
  end
end

if new_object.kind_of?(String)
  return new_object.strip
else
  return new_object
end

```

end

This method can be called like this:

first\_name = get\_value(params, :body, :user, :name, :given)

It will traverse the hash and kick back a nil at the first problem it  
finds instead of raising an exception, or will return the value if it  
actually exists.

Here’s my question, though: is this code efficient? Is there a better  
way? Am I missing something fundamental in Ruby that would solve this  
without the need for the new method?

---

<div class="post-metadata">

**Author:** ![toro04](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ea5d25/32.png) [@toro04](https://www.ruby-forum.com/u/toro04)\
**Post date:** [September 26, 2006, 8:29pm UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096/2 "2006-09-26T20:29:50Z")

</div>

On Wed, 2006-09-27 at 02:55 +0900, removed\_email\_address@domain.invalid wrote:

> It will traverse the hash and kick back a nil at the first problem it  
> finds instead of raising an exception, or will return the value if it  
> actually exists.
> 
> Here’s my question, though: is this code efficient? Is there a better  
> way? Am I missing something fundamental in Ruby that would solve this  
> without the need for the new method?

I think you can rewrite that method like this:

def get\_value(hash, \*path)  
path.inject(hash) { |obj, item| obj[item] || break }  
end

If you’re up for some core-modifying mayhem, You could put it on Hash,  
and extend [] with ‘path’ capabilities:

```
    class Hash
      alias :__fetch :[]

      def traverse(*path)
        path.inject(self) { |obj, item| obj.__fetch(item) || break }
      end

      def [](*args)
        (args.length > 1) ? traverse(*args) : __fetch(*args)
      end
    end

```

This way works like this:

```
    h = {
      :name => {
        :first => 'Ross',
       },
       :contact => {
         :phone => {
           :office => '345345'
        }
      }
    }

    p h.traverse(:name, :first)
    # => "Ross"

    p h.traverse(:name, :middle)
    # => nil

    p h[:contact]
    # => {:phone=>{:office=>"345345"}}

    p h[:contact, :phone, :office]
    # => "345345"

    p h[:contact, :phone, :fax]
    # => nil

```

Of course, there may be better ways to solve the underlying problem…

---

<div class="post-metadata">

**Author:** ![toro04](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ea5d25/32.png) [@toro04](https://www.ruby-forum.com/u/toro04)\
**Post date:** [September 27, 2006, 11:19am UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096/3 "2006-09-27T11:19:11Z")

</div>

> Posted by Adam Traver  
> on 26.09.2006 19:57

> I’ve been having a problem for a while with Ruby where accessing a hash  
> within a hash will fail if the first hash is nil.
> 
> …
> 
> You will receive a hash that looks like this (within the params hash):
> 
> “body” =\> { “user” =\> { “name” =\> { “given” =\> “Tony”, “family” =\> “Robbins” } } }
> 
> Thus, you can access the elements like this:
> 
> params[“body”][“user”][“name”][“given”]
> 
> …
> 
> Here’s my question, though: is this code efficient? Is there a better  
> way? Am I missing something fundamental in Ruby that would solve this  
> without the need for the new method?

Yet another (though indirect) approach could be to first extract all  
keys from the nested hash!

> **[BigBold - Informasi Tentang Bisnis dan Marketing](http://www.bigbold.com)**
>
> BigBold ialah situs yang memberikan segala macam Informasi Tentang Bisnis dan Marketing

---

<div class="post-metadata">

**Author:** ![toro04](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ea5d25/32.png) [@toro04](https://www.ruby-forum.com/u/toro04)\
**Post date:** [September 27, 2006, 7:37pm UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096/4 "2006-09-27T19:37:38Z")

</div>

On 9/26/06, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> </name>
> 
> ```
> 
> params[“body”][“user”][“name”][“given”]  
> if params[“body”][“user”][“name”]  
> end  
> What about:  
> first\_name = params[“body”][“user”][“name”][“given”] rescue nil

Hadley

---

<div class="post-metadata">

**Author:** ![toro04](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ea5d25/32.png) [@toro04](https://www.ruby-forum.com/u/toro04)\
**Post date:** [September 27, 2006, 7:05pm UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096/5 "2006-09-27T19:05:32Z")

</div>

Thanks for all the responses.

Here is the method I ended up with after looking over everything, just  
in case this topic is searched for in the future:

def get\_value(object, \*path)  
for item in path  
break unless object  
object = object ? object[item.to\_s] : nil  
end

```
return object.kind_of?(String) ? object.strip : object

```

end

This might be a little more verbose than some of the solutions (also,  
Ross, your “inject” solution didn’t seem to work out although I’m sure  
it would with some tweaking). However, it ends up doing exactly what I  
need it to do: get the value or return nil, in a quick-and-dirty way.

-Adam

---

<div class="post-metadata">

**Author:** ![toro04](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ea5d25/32.png) [@toro04](https://www.ruby-forum.com/u/toro04)\
**Post date:** [September 27, 2006, 1:30am UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096/6 "2006-09-27T01:30:18Z")

</div>

atraver [gmail.com](http://gmail.com) \<atraver [gmail.com](http://gmail.com)\> writes:

> ```
> first_name = params["body"]["user"]["name"]["given"]
> end
> 
> ```
> 
> end
> 
> That’s not very elegant when you’re doing it with many (15 - 30)  
> fields.

I use something like the following, although it would also look unweildy  
when  
chained together a lot

hsh.fetch(:key, {}) # returns either hsh[:key], or {} if  
!hsh.has\_key?(:key)

so

hsh.fetch(:key1, {}).fetch(:key2, nil) # will work as expected, silently  
returning nil on error

Gareth

---

<div class="post-metadata">

**Author:** ![toro04](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ea5d25/32.png) [@toro04](https://www.ruby-forum.com/u/toro04)\
**Post date:** [September 27, 2006, 11:58pm UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096/7 "2006-09-27T23:58:18Z")

</div>

On Thu, 2006-09-28 at 02:05 +0900, removed\_email\_address@domain.invalid wrote:

> ```
> return object.kind_of?(String) ? object.strip : object
> 
> ```
> 
> end
> 
> This might be a little more verbose than some of the solutions (also,  
> Ross, your “inject” solution didn’t seem to work out although I’m sure  
> it would with some tweaking). However, it ends up doing exactly what I  
> need it to do: get the value or return nil, in a quick-and-dirty way.

Hmm, out of interest, what didn’t work out about it? Maybe I  
misunderstand what you’re doing, but (if you ignore the Hash-extending  
silliness) it seems to work the same.

require ‘test/unit’

def get\_value(object, \*path)  
for item in path  
break unless object  
object = object ? object[item.to\_s] : nil  
end

return object.kind\_of?(String) ? object.strip : object  
end

def my\_get\_value(hsh, \*path)  
path.inject(hsh) { |obj, item| obj[item.to\_s] || break }  
end

class TestGetValue \< Test::Unit::TestCase  
def setup  
@h = {  
‘name’ =\> {  
‘first’ =\> ‘Ross’  
},  
‘contact’ =\> {  
‘phone’ =\> {  
‘office’ =\> ‘345345’  
}  
}  
}  
end

def test\_it  
assert\_equal get\_value(@h, :name, :first),  
my\_get\_value(@h, :name, :first)  
assert\_equal get\_value(@h, :name, :middle),  
my\_get\_value(@h, :name, :middle)  
assert\_equal get\_value(@h, :contact),  
my\_get\_value(@h, :contact)  
assert\_equal get\_value(@h, :contact, :phone, :office),  
my\_get\_value(@h, :contact, :phone, :office)  
end  
end

# -\> 1 tests, 4 assertions, 0 failures, 0 errors

The only thing I changed here is adding to\_s on the item in my version,  
so I could use the same hash to test both while keeping symbol keys.

---

<div class="post-metadata">

**Author:** ![toro04](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ea5d25/32.png) [@toro04](https://www.ruby-forum.com/u/toro04)\
**Post date:** [September 29, 2006, 2:26pm UTC](https://www.ruby-forum.com/t/accessing-nested-hashes-directly/70096/8 "2006-09-29T14:26:10Z")

</div>

removed\_email\_address@domain.invalid wrote:

> without the need for the new method?

I didn’t really like the way that method is called, doesn’t seem very  
“ruby” exactly. Came up with the following which is really dirty at the  
moment but I prefer how it’s called. The method\_missing in NilClass is  
kind of unforgivably dirty. Would like to see improvements I guess, but  
not sure there’s really a way to do this nicely:

So, yeah, don’t use this, but possibly be amused by it anyway:

require ‘ostruct’  
class NestStruct \< OpenStruct  
def self.fromNestedHash(h)  
struct = NestStruct.new(h)  
struct.marshal\_dump.keys.each do |key|  
if struct.send(key).is\_a? Hash  
struct.send(key.to\_s + ‘=’, fromNestedHash(struct.send(key)))  
end  
end  
return struct  
end

def method\_missing(m, \*args)  
super(m, args)  
rescue NoMethodError  
nil  
end  
end

class NilClass  
def method\_missing(m, \*args)  
nil  
end  
end

h = {  
‘name’ =\> {  
‘first’ =\> ‘Ross’  
},  
‘contact’ =\> {  
‘phone’ =\> {  
‘office’ =\> ‘345345’  
}  
}  
}

s = NestStruct.fromNestedHash(h)  
puts s.contact.phone # =\> #  
puts s.contact.phone.office # =\> 345345  
puts s.contact.phone.home # =\> nil  
puts s.foo.bar # =\> nil
