sivanes
sivanes

Reputation: 733

making Session mandatory in a Rails app

I want to make it so that a session has to be present in order to use a site. If not, then redirect to the root path, so that a user can choose whether to browse the site as a guest, log in or register. I'm using a basic authentication made from scratch, based on a Railscast.

in the app controller

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
  before_action :set_artists
  before_filter :check_session
  helper_method :current_user

  private
        def set_artists
            @artists = Artist.all
        end

    def current_user
      @current_user ||= User.find(session[:user_id]) if session[:user_id]
    end

    def check_session
      unless current_user
        redirect_to root
      end
    end
end

I had a guest user logged in, then wiped out all of the guest users through the Rails console: User.where(guest: true).destroy_all. I have a rake task that wipes out guest sessions that are 1 day old, so this would a pretty typical situation. Trying to reload after that, the error comes up: Couldn't find User with 'id'=8

Upvotes: 0

Views: 54

Answers (1)

arrbee
arrbee

Reputation: 241

The problem is that your users will keep their cookies, so when you run:

def current_user
  @current_user ||= User.find(session[:user_id]) if session[:user_id]
end

the user still has the session cookie with a :user_id and the call to User.find is failing to find the now-deleted user.

A solution is to replace this with a call that can fail, such as:

def current_user
  @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
end

Where find will raise an exception if the User cannot be found, find_by will just return nil leaving your current_user empty.

That being said, I agree with the earlier commenter that this is not really the "Rails way." Deleting all the guest users each day is probably not the best way to get the behavior you want.

Instead, one idea is that you could add a timestamp to the User model indicating when the user was last asked to validate as a guest, and then if more than 24 hours have elapsed, you could bounce guest users back to the page that prompts them to register. You don't have to delete their User entry; you can just reuse it when they re-register.

Upvotes: 2

Related Questions