-
-
Save thoughtpunch/1468577 to your computer and use it in GitHub Desktop.
#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? | |
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:
Thing.create!(@results)
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:
a = {}
=> {}
a.try(:'[]', :stuff)
=> nil
a[:stuff] = "awesome"
=> "awesome"
a.try(:'[]', :stuff)
=> "awesome"
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.
Does the hash have to be re-mapped because the keys are different from the attribute names? Or are they the same?