Created
August 23, 2019 09:59
-
-
Save KelseyDH/b8a71a9187331fdcfc5c3aa34fc5af3d to your computer and use it in GitHub Desktop.
Using Null Object pattern in Ruby on Rails apps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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