Rss Feed Tweeter button Facebook button Technorati button Reddit button Linkedin button Webonews button Delicious button Digg button Flickr button Stumbleupon button Newsvine button

A Waage Blog

Ruby, Rails, Life

Archive for the ‘Uncategorized’ Category

Ruby Multi-level Nested Hash Value

with 5 comments

Often in my Ruby code or Rails application, I will need to find a value in a nested hash. Frequently this also comes in handy when dealing with JSON and parsing JSON to a hash. For example, I might have a hash of user information that looks like this:

user_hash = {:id => 1, :name => 'John doe', :extra => {:birthday => {:month => 11, :day => 16, :year => 1951}}}

Now, when I want to find the birthday year, I have to do something messy like this:

year = user_hash[:extra] && user_hash[:extra][:birthday] && user_hash[:extra][:birthday][:year]

How inconvenient is this?! Every level of the hash I am checking for existence of the hash-key. Here’s a helper method that I use so that I can avoid these verbose statements and get the value I want in 1 line. It adds a ‘hash_val’ method to any hash, and takes in the hash-keys as arguments. If one of the nested hash keys is missing, it will simply return nil.

# I usually define this in an initializer, so it can be used all over my app:
# Eg. Place in config/initializers/hash_val.rb
class Hash
  # Fetch a nested hash value
  def hash_val(*attrs)
    attr_count = attrs.size
    current_val = self
    for i in 0..(attr_count-1)
      attr_name = attrs[i]
      return current_val[attr_name] if i == (attr_count-1)
      return nil if current_val[attr_name].nil?
      current_val = current_val[attr_name]
    end
    return nil
  end
end

Now, getting a nested hash value is so easy!

user_hash.hash_val(:extra, :birthday, :year)
 => 1951

And, if the hash-key does not exist, it simply returns nil:

user_hash.hash_val(:extra, :trouble)
=> nil

Written by Andrew Waage

March 18th, 2011 at 8:27 pm