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?
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.