Liz Liz - 5 months ago 6
Ruby Question

Ruby No Method Error on a Model for Current User when Logged Out

I'm building a rails app that has a lot of things that change based on whether or not the user has completed certain quizzes. Everything works fine when a user is logged in, but I just tried logging out and I got a

on this line of code:

<% if current_user.per_quiz.nil? %>

Basically, if the user has completed
they go to one page (the
view), if they haven't they go to a different page (the
view). The only thing that changed was the fact that I logged out, so I can only assume that is what caused the error. Do I need to add some kind of if statement to account for a state in which no user is logged in? How should I fix this error in accordance with Ruby best practices?


You just need to check to see if current_user is set before checking per_quiz. You can handle checking for the login state easily in a view by querying current_user.nil?:

<% if current_user.nil? %>
    <p> You must be logged in to do anything useful.  Please go login</p>
<% elsif current_user.per_quiz.nil? %>
    <p>Cool quiz stuff goes here...</p>
<% else %>

What you probably really want is to have a logged out user go elsewhere, such as the home page or signin page. To do that, you need to do a couple of simple things to your controller. I'm going to assume that the controller is called 'QuizzesController' since you hadn't included your controller code in the question.

Here's how to do it:

class QuizzesController < ApplicationController

  # Other devise authentication logic goes here...

  before_action :authorize_user!

  # Your actions go here...


  def authorize_user!
    if !current_user
      redirect_to '/', notice: "You must be logged in to access to this page"

What this does is install a "before_action" handler that will check that the user is logged in before letting them do anything in this controller. If they are not logged in, you can redirect them wherever you wish.

Note that sometimes, only certain actions need this kind of treatment. In that case, you can use an :only or :except option to specify which action(s) are or are not handled. It looks like this:

  before_action :authorize_user!, only: [ :new, :edit, :create ]

or like this:

  before_action :authorize_user!, except: :list

This will give you greater flexibility in managing the authorization part of the equation, where devise handles the authentication part.