Hash#dig


Has this ever happened to you?

You have a json structure that gets converted into a hash. It has a structure that's a variation on this:

  {
    'product': {
      'title': 'Light saber',
      'type': 'weapon',
      'price': {
        'value': 1000,
        'currency': 'Imperial credits'
      }
    }
  }

Say we want to extract the value attribute from the last level of nesting, so we do:

  response[:product][:price][:value] # ~> NoMethodError: undefined method `[]' for nil:NilClass
  # =>

  # ~> NoMethodError
  # ~> undefined method `[]' for nil:NilClass
  # ~>
  # ~> xmptmp-in2891u-0.rb:8:in `<main>'

But it blows up. So either the :product or :price key is missing, but at this point we don't know which one. So we check for both

  response[:product] && response[:product][:price] && response[:product][:price][:value]
  # => nil

And it works, but it's very ugly.

There has to be another way!

Luckily, there is: The Hash#dig method. This method accepts a succession of keys to navigate though and it returns the value at the end, except that if any of the intermediate keys is missing, it will stop the scan and return nil.

  response = {
    product: {
      title: 'Light saber',
      type: 'weapon',
      price: {
        value: 1000,
        currency: 'Imperial credits'
      }
    }
  }

  response.dig(:product, :price, :value)
  # => 1000

  response = {
    product: {
      title: 'Light saber',
      type: 'weapon',
    }
  }

  response.dig(:product, :price, :value)
  # => nil

I use it all the time at work and hope you're using it too.

See you on the next one.

Saluti.