iswg iswg - 1 month ago 12
Ruby Question

rails ruby double pipe session

I'm trying to make the following work:

1) If I'm a user, I get signed out when I delete my account.

2) If I'm an admin, I stay signed in when I delete other user's account.

It works when I set the current_user method as

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


but when I set it as

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


it gives me this error

ActiveRecord::RecordNotFound in UsersController#destroy
Couldn't find User with 'id'=30


I don't understand why "@current ||=" makes it work.

application_controller.rb

def require_signin
unless current_user
session[:intended_url] = request.url
redirect_to signin_path, notice: "This page requires signin"
end
end

def require_admin
unless current_user_admin?
redirect_to root_path, notice: "Unauthorized Access"
end
end

def current_user_admin?
current_user && current_user.admin?
end

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

def current_user?(user)
user == current_user
end


user_controller.rb

def destroy
@user = User.find(params[:id])
unless current_user?(@user) || current_user_admin?
redirect_to root_path, alert: "Unauthorized Access"
end
@user.destroy
session[:user_id] = nil unless current_user_admin?
redirect_to players_path, alert: "'#{@user.name}' was deleted"
end

Answer

The ||= operator means "set this variable if its not already set".

When you delete the account that you are currently signed in as, you remove the User from the database, however the session[:user_id] is still set to the now deleted User's ID.

Attempting to call User#find with a user ID which has been deleted will result in an ActiveRecord error.

The reason why this does not happen when the ||= operator is present is because the @current variable is already set therefore the User#find is never called.

# this will only try to call User#find if the @current variable is not already set
@current ||= User.find(session[:user_id])

# this will always attempt to call User#find
# if session[:user_id] is set to a deleted user's ID it will raise an error
@current = User.find(session[:user_id])