From: "atraver@..." Date: 2006-09-27T02:55:17+09:00 Subject: Accessing Nested Hashes Directly 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?