Null object pattern examples in Rails

In this post I will explore the NullObject pattern. Why do you need the NullObject pattern? What problem does it solve? How do you implement it?

What is wrong with nil?

If you are a Rails developer you will be used to methods that return nil. The first example that comes to mind is find_by which is typically used like this:

Candidate.find_by(name: 'tom') # => #<Candidate:0x007fd8433ebcf0>
Candidate.find_by(name: 'nobody') # => nil

find_by returns a user if it finds a candidate, otherwise it returns nil.

If you think about this, find_by actually has two return types. It can either return an instance of Candidate or it can return an instance of NilClass. The problem with this is that the caller often needs to do type checking to decide what to do. For example:

def name
  if candidate
    candidate.name
  else
    'N/A'
  end
end

Ruby provides a couple of ways to make checking for nil easier. Ruby 2.3 added the safe navigation operator so you could shorten the if statement above to candidate&.name. However, this is really only masking the problem. You are still handling the special case of nil.

The NullObject pattern

Rather than returning nil, an alternative is to return a NullObject. Instead of returning nil, return NullCandidate. The advantage is that NullCandidate and Candidate share the same interface so no type checking is required.

The implementation of NullCandidate would look something like this:

class NullCandidate
  def name
    'N/A'
  end
end

Lets say I have a method that returns the best candidate of the week. The method receives one argument, which is the name of the candidate of the week. The method uses find_by to find the candidate (which we know returns nil if it doesn’t find anything). Using Ruby’s or operator the method returns an instance of NullCandidate if find_by returns nil.

The logic of type checking for nil is essentially encapsulated inside .candidate_of_the_week and all the callers of the method can assume that they will receive an object that responds to the same interface as Candidate.

class Candidate < ApplicationRecord
  def self.candidate_of_the_week(name)
    find_by(name: name) || NullCandidate.new
  end
end

candidate = Candidate.candidate_of_the_week('tom') #=> #<Candidate:0x007fd843307eb0>
candidate.name #=> 'tom'

candidate = Candidate.candidate_of_the_week('nobody') #=> #<NullCandidate:0x007fd8432e4028>
candidate.name #=> 'N/A'

As you can see, no exception is raised when calling one of candidates methods on NullCandidate.

How can this be applied to Rails?

I’ve been thinking about how to apply the NullObject pattern to Rails. There are lots of resources explaining how to implement the pattern in Ruby but not many that show how it can be applied to Rails. Applying the example above to a Rails app would look like this:

class CandidatesController < ApplicationController
  def index
    @candidates = Candidate.all
    @candidate_of_the_week = Candidate.candidate_of_the_week(params[:name])
  end
end

In the controller we can utilise the .candidate_of_the_week method. In the view we can call methods on the @candidate_of_the_week without worrying about nils. As shown below:

<h2>Candidate of the week</h2>
Name: <%= @candidate_of_the_week.name %>
Email: <%= @candidate_of_the_week.email %>

Example application

You can checkout the whole example on Github. The example demonstrates code before and after the NullObject pattern has been applied.

You can also watch the screencast about this topic.

Further reading

  1. https://robots.thoughtbot.com/rails-refactoring-example-introduce-null-object
  2. http://www.virtuouscode.com/2011/05/30/null-objects-and-falsiness/
  3. https://github.com/avdi/naughthttp://www.sandimetz.com/blog/2014/12/19/suspicions-of-nil