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:
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?