1
votes

I am writing a rails application with devise and testing in rspec. I have an issue where my rspec fails the user_authenticate when the user is not logged in. All of my specs pass except for the last one- the error it gives is

"Failure/Error: get :show, id: course NoMethodError:undefined method `authenticate' for nil:NilClass"

I suspect I am having this issue because I have a before_action :authenticate_user! call and for someone not logged in, it tries to authenticate nil. Is there a way to make it fail gracefully and redirect to user_session? I tried to create an inherited version of authenticate_user to do the redirect, but it does not appear to work. I know this is probably a noob question but I have extensively searched around without any solution. thanks!

This is my controller:

class CoursesController < ApplicationController
    before_action :authenticate_user!, except: [:index]
    before_action :set_course, only: [:show]

    def index
        @course = Course.order('name')
    end

    def show
    end

    private

    def set_course
        @course = Course.find(params[:id])
    end

    def course_params
        params.require(:course).permit(:name,:description,:department,:hidden,
            :lecture_attributes => [:name,:description,:level])
    end

    def authenticate_user!
        if user_signed_in?
            super
        else
            redirect_to user_session
        end
    end

end

This is my spec:

require 'rails_helper'

RSpec.describe CoursesController, :type => :controller do

    describe "user access " do
        before(:each) do
            @user = create(:user)
            @request.env['devise.mapping'] = Devise.mappings[:user]
            sign_in :user, @user
        end

        describe 'GET #index' do
            it 'renders the :index view' do
                get :index
                expect(response).to render_template :index
            end
        end

        describe 'GET #show' do
            it 'assigns the requested course to @course' do
                course = create(:course)
                get :show, id: course
                expect(assigns(:course)).to eq course
            end

            it 'renders the :show template' do
                course = create(:course)
                get :show, id: course
                expect(response).to render_template :show
            end
        end
    end

    describe "guest access " do
        describe 'GET #index' do
            it 'renders the :index view' do
                get :index
                expect(response).to render_template :index
            end
        end

        describe 'GET #show' do
            it 'redirects to the login url' do
                course = create(:course)
                get :show, id: course
                expect(response).to redirect_to 'user_session'
            end
        end
    end
end
2

2 Answers

0
votes

It seems that devise does the redirect to "users#sessions" itself when you add :authenticate_user! to the show action for a guest or a user that is not signed in.

Try removing your custom :authenticate_user! method and add "only: [:show]" to your before_action

class CoursesController < ApplicationController
  before_action :authenticate_user!, only: [:show], except: [:index]
  before_action :set_course, only: [:show]

  def index
      @course = Course.order('name')
  end

  def show
  end

  private

  def set_course
      @course = Course.find(params[:id])
  end

  def course_params
      params.require(:course).permit(:name,:description,:department,:hidden,
        :lecture_attributes => [:name,:description,:level])
  end

end

Update

class CoursesController < ApplicationController
  before_action :authenticate_user!, except: [:index]
  before_action :set_course, only: [:show]

  def index
      @course = Course.order('name')
  end

  def show
      if user_signed_in?
           render :show
      else
           redirect_to user_session
      end
  end

  private

  def set_course
      @course = Course.find(params[:id])
  end

  def course_params
      params.require(:course).permit(:name,:description,:department,:hidden,
        :lecture_attributes => [:name,:description,:level])
  end

end
0
votes

This isn't a super satisfying result but it appears as if authenticate_user! does not properly work with rspec. When I load the page directly, it correctly redirects to the login page, I am still interested to know what the proper work around is.

Can I have some sort of OR statement where I can first check if a user exists? There must be a standard way to deal with this problem so I can ensure my app is properly redirecting.