How to Use Safe Navigation in Ruby

Nurudeen Ibrahim Feb 02, 2024
How to Use Safe Navigation in Ruby

The Ruby Safe Navigation operator(&.) was introduced in Ruby 2.3.0. It allows you to chain methods on an object safely, basically to avoid the popular undefined method for nil:NilClass error.

This article will shortly discuss how to use safe navigation in Ruby.

Use Safe Navigation to Prevent undefined method in Ruby

Example Code:

class Bus
  def seats
    14
  end
end

class Vehicle
  def initialize(name)
    @name = name
  end

  def category
    Bus.new if @name == 'hiace'
  end
end

vehicle = Vehicle.new('camry')
number_of_seats = vehicle.category.seats
puts number_of_seats

Output:

undefined method `seats' for nil:NilClass (NoMethodError)

As seen in the above example, vehicle.category.seats exploded and resulted in an undefined method error because vehicle.category already returns a nil. To avoid this issue, we need to check if the vehicle.category is successful before chaining another method.

The next example, vehicle.category && vehicle.category.seats means if vehicle.category is successful, then vehicle.category.seats should be evaluated, else the code execution should stop and return nil. This works well but can be written with the Safe Navigation Operator.

Example Code:

class Bus
  def seats
    14
  end
end

class Vehicle
  def initialize(name)
    @name = name
  end

  def category
    Bus.new if @name == 'hiace'
  end
end

vehicle = Vehicle.new('camry')
number_of_seats = vehicle.category && vehicle.category.seats
puts number_of_seats

Output:

nil

In this last example, we’ll use another version of Safe Navigation that is more readable and concise. It becomes useful in situations where we have to chain many methods on an object, e.g object1&.method1&.method2&.method3&.method4.

Example Code:

class Bus
  def seats
    14
  end
end

class Vehicle
  def initialize(name)
    @name = name
  end

  def category
    Bus.new if @name == 'hiace'
  end
end

vehicle = Vehicle.new('camry')
number_of_seats = vehicle&.category&.seats
puts number_of_seats

Output:

nil