The safe navigation operator (&.) in Ruby

Last updated on December 20, 2021

Ruby 2.3.0 introduced the Safe Navigation Operator &.. Over the last couple of months, the safe operator has played a big part of the programming flow of my team (mainly due to the CMS integration with the marketing website) and it has saved us many lines of code. Let’s explore what it is and what are the pros and cons of using it.

Comparison to try!

A lot of comparison can be drawn from Ruby’s try! method and the safe operator &.

However, there are several differences that you should be aware of.

Method name is syntactically required when using &.

obj.try! {} # valid
obj&. {}    # syntax error

When using the &. attribute, the assignment is valid

obj&.attr = "Tobias Funke" # valid
obj.try!(:attr) = "Tobias Funke" # syntax error

Generally speaking, the safe operator is better compared to Rails’ try or Ruby’s try! (even though that this might be subjective depending on the developer). There are several points for this argument

Performance of the safe operator

Regarding my last point, I came across this benchmark which compared the safe operator against other common methods for testing for nil.

The safe operator had a similar speed compared to a simple check for nil && nil.length and it was ~4 times faster compared to Rails’ try method.

Why do we need it?

In some cases, our object might be nil which might break our code if we call a specific method on that object. We might want to prevent our app from raising an error and the safe operator &. will do exactly that - it will return nil after our method call even if our object is nil.

Example

Let’s say that we have a user with a team and we want to get the name of that team. If the user is present, it will work as expected.

user.team.name
=> "The Bluth Company"

But what if the the user is not present?

user
 => nil
user.team
Traceback (most recent call last):
        1: from (irb):9
NoMethodError (undefined method `team' for nil:NilClass)

One solution is to create an if statement

if user.present?
  teamName = user.team.name
else
  teamName = nil
end

Or we can use the safe operator

teamName = user&.team.name
 => nil

Let’s expand this problem further. What if the user is present, but it doesn’t have a team?

teamName = user&.team.name
Traceback (most recent call last):
        1: from (irb):33
NoMethodError (undefined method `name' for nil:NilClass)

We can quickly fix this error using a safe operator.

teamName = user&.team&.name
 => nil

Why you might not want to use the safe operator

While conducting my research for this article, I found some comments and articles that criticize the safe operator. Even though these comments might have merit, I think it is a great addition to the toolkit of a Rails developer.

I learnt that there are several potential problems with the safe operator that you should be aware of.

Invite us to your inbox.

Articles, guides and interviews about web development and career progression.

Max 1-2x times per month.