The Null Object Pattern is a great tool for removing conditionals in your code base. Rather than checking for nil or predicates about an object existing, you instead return a “null” implementation that responds to the same interface. The most common case I’ve applied this to in my Rails apps is the concept of a “Guest User”. For example:

class Guest def email "" end def admin false end alias_method :admin? , :admin def purchases [] end end class ApplicationController < ActionController :: Base include Clearance :: Controller def current_user super || Guest . new end end

This implementation can serve us quite well. Our code base expands, blissfully unaware of whether it’s dealing with a User or a Guest . As we add logic for our store front, we end up with methods like this:

class StoreListing < ActiveRecord :: Base def included_in? ( purchases ) purchases . map ( & :store_listing_id ). include? ( :id ) end end

Things will continue to work on our empty array, as long as we are only calling methods from the Enumerable module. However, we run into problems as soon as we write some code like this:

class CategoryStoreController < ApplicationController def index redirect_to ( subcategory_store_path ( subcategory_for_redirect )) end private def subcategory_for_redirect last_purchase_in_category . subcategory || category . subcategory . first end def last_purchase_in_category @last_purchase_in_category ||= current_user . purchases . last_in_category ( category ) end def category @category ||= Category . find ( params [ :id ]) end end

If the user isn’t logged in, this will fail with NoMethodError: undefined method 'last_in_category' for []:Array .

Luckily, Rails 4.0 introduced a new method on ActiveRecord::Relation to help with exactly this situation! Relation#none is a method that will return a new instance of NullRelation .

NullRelation responds to every method that a normal instance of Relation would. As a bonus, when you call .none on one of your model classes, it will also respond to all of the class methods that a Relation for that class would have held as well! Our updated Guest class would look like this:

class Guest def purchases Purchase . none end end

Once we’ve utilized Relation#none in our null objects, the rest of our code works as expected, and we can continue blissfully unaware of the existence of Guest in the rest of our codebase.

For those of you who haven’t upgraded to Rails 4 yet (you probably should…), you can achieve a similar effect with this simple back-port:

class ActiveRecord::Base def self . none where ( "1 = 0" ) end end

This isn’t quite the same as NullRelation . It’ll still hit the database and try to load data, and the call to none could be undone with .unscope(:where) . However, for most cases it should act as a suitable polyfill until you’re able to upgrade to Rails 4.

If you enjoyed this article, you might also enjoy: