Created
December 12, 2011 18:58
-
-
Save thoughtpunch/1468577 to your computer and use it in GitHub Desktop.
A Better Way to iterate through arrays/hashes with nils?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Let say I'm getting back a JSON nested hash (or array of hashes) from an API | |
@example = {"results" = > {{"poop" => "shoop"},{"foo" => {"shizz" => "fizz", "nizzle"=>"bizzle"}}} | |
# YAML VIEW OF ABOVE | |
#- poop: shoop | |
#- foo: | |
# shizz: fizz | |
# nizzle: bizzle | |
#Now lets go make a db entry with ActiveRecord from the hash. This should work fine. | |
Thing.create!(:poop => @example["results"]["poop"], | |
:shizz => @example["results"]["foo"]["shizz"], | |
:nizzle=> @example["results"]["foo"]["nizzle"]) | |
# But what if 'foo' is empty or nil? For example, if an API result has a "person" hash with "first name","last name" # etc, the "person" hash will usually be empty if there is no data, which means the hashes inside it don't exist. | |
# such as this example: | |
@example = {"results" = > {{"poop" => "shoop"},{"foo" => nil }} | |
Thing.create!(:poop => @example["results"]["poop"], | |
:shizz => @example["results"]["foo"]["shizz"], | |
:nizzle=> @example["results"]["foo"]["nizzle"]) | |
#NoMethodError: You have a nil object when you didn't expect it! | |
#You might have expected an instance of Array. | |
#The error occurred while evaluating nil.[] | |
#What's the best way to handle this? | |
I also asked this question on SO and got the same answer, as well as a monkey patch for 'Hash' that should do the trick.
http://stackoverflow.com/questions/8479476/iterating-through-a-ruby-nested-hash-with-nils
class Hash
def get(key, default=nil)
key.split(".").inject(self){|memo, key_part| memo[key_part] if memo.is_a?(Hash)} || default
end
end
h = { 'a' => { 'b' => { 'c' => 1 }}}
puts h.get "a.b.c" #=> 1
puts h.get "a.b.c.d" #=> nil
puts h.get "not.here" #=> nil
Doh, that's right, try is Rails-only. I personally wouldn't monkeypatch Hash like that. Better to create a special method that handles it.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What I was getting at is, if the hash returned was a one-to-one representation of the model, I think you could literally just pass the whole thing in, nils and all:
But if you need to re-map it, and or cherry-pick keys out, then that won't work. Another solution might be to use the try method. You pass in a symbol, and it will attempt to call that method. But if there's a NoMethodError error it will just return nil. To do this with a hash would look something like this: