DEV Community

Prathamesh Sonpatki
Prathamesh Sonpatki

Posted on • Originally published at prathamesh.tech on

Diggin through hashes and arrays in Ruby

Diggin through hashes and arrays in Ruby

While working with third party APIs, lot of times we get nested JSON structure in the response. Here is sample response from GitHub API.

[
  {
    "id": 1,
    "title": "Found a bug",
    "body": "I'm having a problem with this.",
    "user": {
      "login": "octocat",
      "id": 1,
    },
    "labels": [
      {
        "name": "bug"   
      }
    ],
    "assignee": {
      "login": "octocat",
    },
    "assignees": [
      {
        "login": "octocat"       
      }
    ],
    "milestone": {      
      "creator": {
        "login": "octocat"
      },
      "open_issues": 4,      
    },
    "pull_request": {
      "url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347"
    },
    "closed_at": null,
    "created_at": "2011-04-22T13:33:48Z",
    "updated_at": "2011-04-22T13:33:48Z"
  }
]
Enter fullscreen mode Exit fullscreen mode

Once we parse this with JSON.parse we get a nested hash object. To reach the creator of the milestone of an

issue, we need to reach it as follows.

issues = JSON.parse(issues_params)
issue.each do |issue|
  creator = issue[:milestone][:creator][:login]
end
Enter fullscreen mode Exit fullscreen mode

Do you spot any problem with this piece of code? If the issue[:milestone] is nil then this code will fail.

We can solve this by checking if issues[:milestone] is not nil then try to access the creator. But what if

issue[:milestone][:creator] is nil?

issues = JSON.parse(issues_params)
issue.each do |issue|
  creator = issue[:milestone] && issue[:milestone][:creator] && issue[:milestone][:creator][:login]
end
Enter fullscreen mode Exit fullscreen mode

Instead we can use my most favorite method from Ruby which is dig.

This method is available from Ruby 2.3 onwards.

Digging through nested hashes

Ruby provides a method Hash#dig which can be used in this case. As the name suggests, the method digs through the nested hash looking for keys we asked it to look for. If it finds out any key which is not present, it just returns nil. Let's write above code using the Hash#dig method.


issue.each do |issue|
  creator = issue.dig(:milestone, :creator, :login)
end
Enter fullscreen mode Exit fullscreen mode

If issue[:milestone] or issue[:milestone][:creator] is nil then this method will simply return nil instead of resulting into an error.

Digging arrays

Array class in Ruby also provides dig method.

h = { colors: ["red", "blue", "yellow", "green"] }
irb(main):013:0> h.dig(:colors, 0)
=> "red"
irb(main):014:0> h.dig(:colors, 2)
=> "yellow"

Enter fullscreen mode Exit fullscreen mode

Liked this article about handling nested hashes and arrays in Ruby? You will like my other articles about Ruby and Rails as well. Don't miss any of my blogs by subscribing to my newsletter!

Discussion (2)

Collapse
burdettelamar profile image
Burdette Lamar

Thanks, Prathamesh.

The nested objects may include any that respond to #dig,
which includes instances of:

  • Hash
  • Array
  • Struct
  • OpenStruct
  • CSV::Table
  • CSV::Row
Collapse
prathamesh profile image
Prathamesh Sonpatki Author

Nice! Thanks Burdette! Didn't know that.