Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: replacing try with the Null Object Pattern

In most of my applications, I have a current_user method. To avoid exceptions in cases like current_user.name where current_user is nil, rails provides the try method. The problem with this is that I need to remember to use try wherever current_user might be nil.

I want to use the Null Object pattern to remove this additional overhead.

class NullUser
  def method_missing(method_name, *args)
    nil
  end
end

def current_user
  return NullUser.new unless UserSession.find
  @current_user ||= UserSession.find.user
end

This can replace try in some cases:

current_user.try(:first_name)     #=> nil
current_user.first_name           #=> nil

but fails with further chaining:

current_user.profiles.first.name    #=> undefined method...

I tried to return the null object:

class NullUser
  def method_missing(method_name, *args)
    self.class.new
  end
end

current_user.try { |u| u.profiles.first.name }  #=> nil
current_user.profiles.first.name                #=> nil

but this would fail in other cases:

current_user.is_admin?            #=>  #<NullUser:0x96f4e98>

Is there a possible solution to this problem or do we all have to live with try?

like image 867
Alex Avatar asked Apr 18 '13 07:04

Alex


2 Answers

I would stick with the NullUser but change its name to GuestUser to make things clearer. Additionally you should stub all important method from your User class, e.g.

class GuestUser
  def method_missing(method_name, *args)
    nil
  end

  def is_admin?
    false
  end

  # maybe even fields:
  def name
    "Guest"
  end

  # ...
end
like image 77
Marian Theisen Avatar answered Nov 06 '22 07:11

Marian Theisen


If you want to be able to chain methods on your NullUser instance, you need to have method_missing return self instead of nil. You attempt with returning self.class.new was close ...

Avdi Grim explains how to implement a Null Object pattern in Ruby.

like image 43
Jonny Appleseed Avatar answered Nov 06 '22 08:11

Jonny Appleseed