Search code examples
ruby-on-railsrspecrspec-rails

Rspec tests with before_action and current_user (as in Hartl tutorial)


I've just figured out a reason some of my tests continually failed, but the way I've fixed it doesn't seem right. I'd like to know whether this can be improved.

I have a controller action, index, that looks like this.

class StuffController < ApplicationController
    before_action :signed_in_user

    def index
        @stuff = current_user.stuff
    end
end

The signed_in_user method, straight from the tutorial:

def signed_in_user
    unless signed_in?
        store_location
        redirect_to signin_url, notice: "Please sign in."
    end
end

When I test the case that the /stuff endpoint is accessed without signing in, the test fails because:

Failure/Error: get "/stuff"
     NoMethodError:
       undefined method `stuff' for nil:NilClass

I know now that this is because, despite the before_action causing the response to redirect to signin_url, the index action is still executed in full. I changed the action to this to fix it:

def index
    @stuff = current_user.stuff unless current_user.nil?
end

It seems like there ought to be a way to force the redirect to cease executing the rest of the code, rather than dirtying up each action with two checks for current_user.nil?. I did try adding redirect_to signin_url, notice: "Please sign in." and return, but that didn't work.

Is this the right/rails way, or can it be improved?


Solution

  • The reason my tests were failing was because I forgot to add the no_capybara: true option when signing in with the helper function from the tutorial. Since this was a request spec, capybara DSL isn't automatically available. The correct/rails answer is:

    it "does something when logged in" do
      before { sign_in @user, no_capybara: true }
      expect(stuff).to be_stuff
    do
    

    The sign_in helper method is shown here.