Skip to content

Instantly share code, notes, and snippets.

@KelseyDH
Created August 23, 2019 09:59
Show Gist options
  • Save KelseyDH/b8a71a9187331fdcfc5c3aa34fc5af3d to your computer and use it in GitHub Desktop.
Save KelseyDH/b8a71a9187331fdcfc5c3aa34fc5af3d to your computer and use it in GitHub Desktop.
Using Null Object pattern in Ruby on Rails apps
# E.g. for a banking app where users might not have bank accounts yet.
# Not having accounts could mean lots of code like this:
if user.savings_account.present?
user.savings_account.available_balance_cents
end
# But with the NullObject pattern I can confidently call:
user.savings_account.available_balance_cents
# because in the background my model has me covered:
class User < ApplicationRecord
def savings_account
self.accounts.where(savings: true).first || NullAccount.new
end
end
# domain/null_account.rb
class NullAccount
def id
raise "You are calling id on an account that doesn't exist. Make sure the user you're working with has accounts first before trying to call them."
end
def available_balance
Money.new(available_balance_cents, available_balance_currency)
end
def available_balance_cents
0
end
def available_balance_currency
"CAD"
end
def valid?
false
end
def present?
false
end
def blank?
true
end
def account_key
raise "account_key is being called on a NullAccount!!"
end
def currency
"CAD"
end
def save
raise ActiveRecord::RecordInvalid
end
def update
raise ActiveRecord::RecordInvalid
end
end
# This pattern can be extended for other use cases, such as representing a fake user.
# E.g. when working with the papertrail gem that records who makes database changes,
# you can create a `SystemUser` as a fake user to represent changes to data made by scheduled jobs, data migrations etc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment