I have used omniauth-salesforce in my sessions controller I have following code, even when I logout the session is still present, I have tried session.clear and reset_session in destroy method but nothing works, sign in works only after clearing browser cache
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url
end
def destroy
session[:user_id] = nil
redirect_to root_url
end
end
How to delete session on signout?
Session is similar to a normal hash so below thing should work.
session.delete(:user_id)
Use this
session[:user_id] = nil if session[:user_id]
Related
I'm going through Michael Hartl's The Ruby on Rails Tutorial, Chapter 8.3 Logging Out Sessions and I don't understand how removing the session[:user_id] can remove the #current_user as well:
here is the SessionController:
class SessionsController < ApplicationController
def new
end
def create
user =User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in(user)
redirect_to user
else
#flash.now will only flash once - if a new request or view is rendered,the flash will go away now
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
log_out
redirect_to root_path
end
end
and here is the SessionsHelper for the login and logout helpers:
module SessionsHelper
def log_in(user)
session[:user_id] = user.id
end
def current_user
#find the user if #user is not defined yet, or else, just keep the current user
#that way we dont have to do a database search every time current_user is called
#current_user ||= User.find_by(id: session[:user_id])
end
def logged_in?
!current_user.nil?
end
def log_out
session.delete(:user_id)
end
end
The way I understand, once #current_user is defined once logged in, shouldn't the variable still last even though the session[:user_id] has been removed since it is being set to itself?
#current_user ||= User.find_by(id: session[:user_id])
There was no action that I am aware of that removed the #current_user variable. But when I tested it during the debugger, I can see that once someone logs out, #current_user becomes nil.
Can someone explain the mechanics to me?
The session persists between requests. But the instance variable #current_user only persists for the length of one request. When the destroy action redirects to the root_path that is the start of a new request which will load the root page.
You may want to try this out so see that clearing the user_id out of the session doesn't clear out the instance variable:
def destroy
# Test code to initialize #current_user
current_user
Rails.logger.debug("#current_user before: #{#current_user.inspect}")
log_out
# Test code to check #current_user after updating session
Rails.logger.debug("#current_user after: #{#current_user.inspect}")
redirect_to root_path
end
And then check what ends up in log/development.log. #current_user will still be present after log_out but it will go away at the end of the request.
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
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])
Im new to Rails and having troubles trying to destroy the user session.
My session controller looks like this
class SessionsController < ApplicationController
def new
end
def create
name = params[:name]
password = params[:password]
user = User.authenticate(name, password)
if user.nil?
render json: {isLogin: false}
else
session[:user_id] = user.id
render json: {isLogin: true}
end
end
def destroy
session[:user_id] = nil
puts session[:user_id] # Nothing gets printed to the console here
render json: {isLogin: false}
end
end
When I call 'sessions/destroy' and try to destroy the session, nothing gets printed at 'puts session[:user_id]' line. So I know for sure that the session is nil at that point. But the problem is that I can still access the session like this from a different controller even after I destroy the session for that user.
class LessonsController < ApplicationController
def getLesson
userId = session[:user_id]
# do stuff
end
end
Why is this happening? and how can I fix this?.
Try
session.delete(:user_id)
instead of
session[:user_id] = nil
That is what I have had luck with in the past.
So I am building an application that I am trying to never need a database as the application will just be a portal to an API. I have a sessions controller and I am trying to use a cookie based session but the setter method is never being hit. Here is what I have at this point.
sessions_controller.rb
class SessionsController < ApplicationController
def new
if current_user
redirect_to snapshots_path
end
end
def create
api = API.new
response = api.authenticate_user(params[:session][:username].downcase, params[:session][:password])
if response["Message"] == "success"
current_user = response["User"]
binding.pry
redirect_to snapshots_path, notice: "Signed in successfully."
else
flash.now[:error] = "Invalid username/password combination."
render :new
end
end
def destroy
current_user = nil
redirect_to sign_in_path
end
end
sessions_helper.rb
module SessionsHelper
def current_user=(user)
binding.pry
if user
#current_user = user
cookies[:userdata] = { :value => user, :expires => 8.hours.from_now.utc }
else
#current_user = nil
cookies.delete(:userdata)
end
end
def current_user
binding.pry
#current_user ||= (cookies[:userdata] ? cookies[:userdata] : nil)
end
end
The getter method is hit correctly every time but the setter is never getting hit. Any ideas as how to fix this thanks.
When you are assigning to current_user it's treating it as a local variable. To solve that simply assign to self.current_user instead. The getter doesn't need that because there is no local variable named that so ruby looks for a method and uses that. If you reference the getter as self.current_user that would also work.
For example change:
current_user = response["User"]
to:
self.current_user = response["User"]
Include SessionsHelper in your SessionsController in order to access SessionHelper methods within SessionsController.
Code will work fine without any modification i.e., you would be able to access current_user and current_user= directly.
class SessionsController < ApplicationController
include SessionsHelper ## Just add this
..
end
I am trying to redirect to the page from where I clicked login, but after logining in it doesn't redierect to previous page but stays on login page (although the user is already logged in).
Here is my code:
session_helper.rb
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
session.delete(:return_to)
end
def store_location
session[:return_to] = request.fullpath
end
end
sessions_controller.rb
class SessionsController < ApplicationController
include SessionsHelper
def new
end
def create
user = User.find_by_username(params[:session][:username])
if user && user.authenticate(params[:session][:password])
cookies.permanent[:remember_token] = user.remember_token
#redirect_to root_url,:notice => "Logged in!"
redirect_back_or user
else
flash[:error] = 'Invalid email/password combination' # Not quite right!
render 'new'
end
end
def destroy
cookies.delete(:remember_token)
#session[:user_id] = nil
redirect_to root_url, :notice => "Logged out!"
end
end
I also tried to write in create function in sessions_controller.rb
redirect_to request.referer
but it doesn't work.
Am I missing something?
Thanks for your help!
The problem happens at store_location.
Though you havn't said in question, I guess you probably put this method in before_filter. So, no matter GET or POST or other request, the request hit this filter at first and store location.
Now, in this case, actually the user has two requests. One is to #new by GET, and the other is to #create by POST. In the later, his last request to #new was recorded as the going back location. So you'll see you always go back to #new :)
The solution is to filter the location to be stored.
def store_location
disable_pattern = /\A\/user*/
session[:return_to] = request.fullpath unless request.fullpath ~= disable_pattern
end
This pattern could solve current problem but not exclusive. In practice you may see even JS/JSON requests has been recorded, so you may need to add more restrictions according to the specific case. For example, only apply before_filter on #show or #index, use white list, etc.
I think request.referer may not have worked because of a typo in the method. It should be request.referrer.