How to handle Ruby find command return undefined method `[]' for nil:nilclass (nomethoderror)

57 Views Asked by At

I’m using the Ruby find command to collect the information I need from the Puppet Database as below.

vm_name = puppetdb.find { |details| details['certname']==(hostname) and details['name'] == 'az_metadata' }['value']['compute']['name']

Some of the parameters don’t have ‘az_metadata’ parameters, and that causes the find function to show “undefined method `[]' for nil: nil class (no method error).” How can I handle those or undefined method values from the find result for that specific variable?

How can I handle those or undefined method values from the find result for that specific variable?

2

There are 2 best solutions below

2
borjagvo On

From the error, it seems the value to a key in the results is nil.

You can use dig method or the Safe Navigation Operator

# dig
data = puppetdb.find {|details| details['certname']==(hostname) and details['name']=='az_metadata'}
vm_name = data.dig('value','compute','name')

# Safe Navigation
data = puppetdb.find {|details| details['certname']==(hostname) and details['name']=='az_metadata'}
vm_name = data&.['value']&.['compute']&.['name']
0
John Bollinger On

Some of the parameters don’t have ‘az_metadata’ parameters, and that causes the find function to show “undefined method `[]' for nil: nil class (no method error).” How can I handle those or undefined method values from the find result for that specific variable?

Test whether the result is nil before trying to access its elements? There are fewer ways to do that in Ruby 2.0 than in some later versions, but any version you're likely to be able to put your hands on should accept this:

result = puppetdb.find { |details| details['certname']==(hostname) and details['name'] == 'az_metadata' }

vm_name = result.nil? ? nil : result['value']['compute']['name']

You can of course substitute a different default value for the case where puppetdb.find returns nil.

Of course, if you cannot rely on the result to have a 'value', and that to have a 'compute' then the problem occurs again, and you might need to do the above multiple times.

Alternatively, if you scope it narrowly enough, it could be reasonable to just rescue the NoMethodError:

result = puppetdb.find { |details| details['certname']==(hostname) and details['name'] == 'az_metadata' }

begin
  vm_name = result['value']['compute']['name']
rescue NoMethodError
  vm_name = nil
end

Note, however, that that leaves it ambiguous what was nil, and that it would also catch cases where the result or one of the other intermediate values was non-nil but also did not have a [] method.