Null Object pattern with Devise

I was googling but couldn’t find any examples of using Devise and Null Object pattern. I just want to check if anyone else sees a potential problem with the code below. Here’s what I came up with:

# application_controller.rb
def current_user
  @current_user ||= warden.authenticate(scope: :user) || Guest.new
end

This way no other changes are required in the controller/view layer (you still refer to current_user as before).

Thanks for your thoughts.

Looks good? Do the tests pass? :smile:

Nice one, Ben! :slight_smile: I don’t currently have any controller specs that would catch possible misbehaviour while existing integration specs and unit tests run fine.

I think I’ve done exactly what you’re doing but with Clearance in the past. It worked fine. I suspect it will work with Devise too.

You can check thoughtbot’s last blog post. :wink:

Can you do this instead:

# application_controller.rb
def current_user
  @current_user ||= super || Guest.new
end

The drop down to warden methods worries me because it seems like an implementation detail of devise. I don’t have much experience with Devise, though.

2 Likes

Thats a good improvement! I didn’t think of super before. It is true - not worrying about Devise’s implementation feels much better than using warden’s methods directly. Thanka a lot. And now off to read latest blog post and finish my coffee :slight_smile:

The above implementation broke a few of my tests, I ended up modifying it to avoid creating the NullUser when inside a devise controller:

  def current_user
    if devise_controller?
      @current_user = super
    else
      @current_user ||= super || AnonymousUser.new
    end
  end

@derekprior I have also implemented the null user object using devise, however it broke the user_signed_in? method.

I originally posted this on stack overflow but had no response, but was able to figure out I must have to override this method too.

I have posted what I came up with on there, and was wondering if someone knows a better way or they can re factor it in any kind of way? The link is here

Thanks

I don’t know how devisse implements user_signed_in? but I’m guessing it’s just checking the current_user is not nil. You’ll probably need to override that to also make sure it’s not a guest. Something like:

def user_signed_in?
  super && !current_user.is_a(Guest)
end