The Problem: Dealing with nil Values

In Ruby on Rails, it’s common to work with associations and optional data. For example, consider the following code:

class User < ApplicationRecord
  belongs_to :account, optional: true
end

When an account is missing, you often check for nil to avoid errors:

if user.account
  user.account.name
else
  "Guest"
end

This pattern leads to repetitive if conditions, cluttering code and increasing the risk of NoMethodError when a nil value is accessed accidentally.

Enter the Null Object Pattern

The Null Object Pattern solves this by providing a default object to replace nil. Instead of checking for nil, the object responds to the same methods as the actual object, but with neutral behavior.

Example: Without Null Object

class Account < ApplicationRecord
  # ... some methods
end

class User < ApplicationRecord
  belongs_to :account, optional: true

  def account_name
    account ? account.name : "Guest"
  end
end

Example: With Null Object

class NullAccount
  def name
    "Guest"
  end
end

class User < ApplicationRecord
  belongs_to :account, optional: true

  def account
    super || NullAccount.new
  end
end

Now, you can safely call user.account.name without worrying about nil.

Advantages of Using Null Object

  1. Cleaner Code: Removes repetitive nil checks.
  2. Reduced Errors: Prevents NoMethodError when accessing nil.
  3. Improved Readability: Methods are easier to understand without conditional logic.

Advanced Usage: Null Object with Polymorphism

The Null Object can also implement additional methods or mimic the behavior of its real counterpart:

class NullAccount
  def name
    "Guest"
  end

  def active?
    false
  end
end

With this approach, you can call methods like user.account.active? without worrying about nil.