Intro

If you’ve been programming in Ruby for any amount of time, you’ve probably seen an error like this:

NoMethodError: undefined method 'methodname' for nil:NilClass

Understanding the Exception

The meaning is actually pretty straightforward if you think about it. We’re trying to call a method called “methodname” that is not defined for the object we’re calling it on. In this case, that object is nil:

a = nil
a.methodname()
#=> NoMethodError: undefined method `methodname' for nil:NilClass

However, nil isn’t special here, other classes do throw the same error:

a = "string"
a.methodname()
#=> NoMethodError: undefined method `methodname' for "string":String

We’re only really focusing on the case where an undefined method is called on nil though. I just thought it was important to point out.

Anyways, probably the most common method you’ll see this happen with is: []

NoMethodError: undefined method `[]' for nil:NilClass

Problematic Example

You might see something like this when you’re pulling data out of a nested data structure you receive over HTTP or some other protocol:

response1 = [1, 2, [3, 4]]

response2 = [1, 2, [1, 2]]

response3 = [ 1, [3, 4]]


def process_response(response)
  puts response[2][1] + response[0]
end

process_response(response1)
#=> 5

process_response(response2)
#=> 3

process_response(response3)
#=> NoMethodError: undefined method `[]' for nil:NilClass

In the above code, we assumed that every response would have a nested array as the third element of the outer array. Of course, this was not the case for response3. There is no third element in response3, so nil is returned. We then try to run the [] method on that nil and that’s when we generate the NoMethodError:

response3[2]
#=> nil

nil[1]
#=> NoMethodError: undefined method `[]' for nil:NilClass

A Fix for Our Example

Let’s fix it:

def process_response(response)
  if response[2] && response[2][1] && response[0]
    puts response[2][1] + response[0]
  end
end

process_response(response3)
#=> nil

Well, that’s pretty tedious, there must be a better way. Enter the safe navigation operator!: &

A Better Fix: Safe Navigation Operator

def process_response(response)
  puts response[2]&[1] + response[0]
end

That’s it, did you even notice? All we have to do is put a & between our possibly-nil object, and the method being called on it. If the object is nil, the method won’t be called, and nil will be returned instead of an exception.

So much easier than checking every single item manually!

Thoughts for the reader:

  • Is there a better way to handle this?
  • Where else might you run into errors like this?