Safe navigation equivalent to Rails try for hashes

Ruby on-RailsRuby

Ruby on-Rails Problem Overview


In Rails, you can do hash.try(:[], :key) which helps if hash is potentially nil. Is there an equivalent version for using the new Ruby 2.3 safe navigation operator &. with []?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

&. is not equivalent to Rails' try, but you can use &. for hashes. Just use it, nothing special.

hash[:key1]&.[](:key2)&.[](:key3)

Although I would not do that.

Solution 2 - Ruby on-Rails

Ruby 2.3 and later

There's Hash#dig method now that does just that:

> Retrieves the value object corresponding to the each key objects repeatedly.

h = { foo: {bar: {baz: 1}}}

h.dig(:foo, :bar, :baz)           #=> 1
h.dig(:foo, :zot)                 #=> nil

http://ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig

Pre Ruby 2.3

I usually had something like this put into my intializer:

Class Hash
    def deep_fetch *args
      x = self
      args.each do |arg|
        x = x[arg]
        return nil if x.nil?
      end
      x
    end
end

and then

response.deep_fetch 'PaReqCreationResponse', 'ThreeDSecureVERes', 'Message', 'VERes', 'CH', 'enrolled'

in one wacky case.

The general consensus in the community seems to be to avoid both try and the lonely operator &.

Solution 3 - Ruby on-Rails

While hash&.[](:key) is elegant to the trained rubyist, I'd just use hash && hash[:key] as it reads better and more intuitively for the programmer coming after me, who may not be as familiar with the intricacies of ruby. Some extra characters in the codebase can sometimes save a whole lot of googling for someone else.

(Given the context you want to use this in is in a conditional statement, of course.)

Solution 4 - Ruby on-Rails

A rather more legible way to use the safe navigation operator than using hash&.[](:slug) is to use the fetch method:

hash&.fetch(:slug)

If your key may not be defined, you can use the second argument as a default:

hash&.fetch(:slug, nil)

Solution 5 - Ruby on-Rails

Accepted answer will not account for when hash is nil...

You can rewrite what you have using the safe nav operator before the .try and that will work

hash&.try(:[], :key)

but you can also use:

http://ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig

A way you could do this on a hash is by doing...

hash&.dig(:key1, :key2 ...)

which will return nil if any key fetch isn't present.

{ key1: { key2: 'info' } } 

would return 'info'

{ key1: { wrong_key: 'info' } } 

would return nil

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJacob MurphyView Question on Stackoverflow
Solution 1 - Ruby on-RailssawaView Answer on Stackoverflow
Solution 2 - Ruby on-RailsbbozoView Answer on Stackoverflow
Solution 3 - Ruby on-RailsMagneView Answer on Stackoverflow
Solution 4 - Ruby on-RailsSunnyView Answer on Stackoverflow
Solution 5 - Ruby on-Railsbf34View Answer on Stackoverflow