Rails session[:user_id] wont destroy - ruby-on-rails

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.

Related

How to bind Act_as_shopping_cart with user

i am doing my first project and i need your help.
I am using act_as_shopping_cart gem, and user model like in Rails Tutorial.
How can i bind user and shopping cart? I tried bound shopping_cart.id and user.id, but without succes, still all users have same cart.
It my code:
Shopping cart controller:
class ShoppingCartsController < ApplicationController
before_filter :extract_shopping_cart
def create
#product = Sketchbook.find(params[:product_id])
#shopping_cart.add(#product, #product.price)
redirect_to shop_path
end
def show
end
private
def extract_shopping_cart
shopping_cart_id = session[:shopping_cart_id]
#shopping_cart = session[:shopping_cart_id] ? ShoppingCart.find(shopping_cart_id) : ShoppingCart.create
session[:shopping_cart_id] = #shopping_cart.id
end
end
User controller:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:show, :edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to user_url(#user)
flash[:notice] = "Użytkownik stworzony"
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
redirect_to user_url(current_user)
flash[:notice] = "Dane zaktualizowane"
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "Konto usunięte"
redirect_to root_url
end
private
def user_params
params.require(:user).permit(:username, :name, :surname, :email, :adress, :city, :zip_code, :country, :password, :password_confirmation)
end
#confirms a logged user
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Zaloguj się"
redirect_to login_url
end
end
#confirms the correct user
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
Session helper:
module SessionsHelper
#log in method
def log_in(user)
session[:user_id] = user.id
end
#remember a user in a presisnet session
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
#returns true if the given user i current user
def current_user?(user)
user == current_user
end
#forgets a presistent session
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# returns logged user
def current_user
if (user_id = session[:user_id]) #open broweser
#current_user ||= User.find_by(id: session[:user_id])
elsif (user_id = cookies.signed[:user_id]) #cookie is present
user= User.find_by(id: cookies.signed[:user_id])
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
# Returns true if the user is logged in
def logged_in?
!current_user.nil?
end
# logs out current user
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil?
end
#stores the url trying to be accessed
def store_location
session[:forwarding_url] = request.url if request.get?
end
#redirect back to stored location (or to the default)
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
end
I'd also happy if you could give me some other guidances how to improve this code.
Rails lets you do lots of "magic" where code in one place magically affects behavior elsewhere in the app, with no explicit connection between the two. This is really powerful but I think is also a huge problem for beginning developers; when you're learning Rails, it's super hard to keep track of how one thing is related to another so having those connections hidden up in the inheritance chains is almost cruel.
So if you're in a place where the Rails magic is overwhelming (it certainly still is for me), my advice is to write stupid code that makes connections as local and simple as possible. Sometimes it's worth doing that even when it deviates from "the Rails way"; would you rather have "proper Rails" code, or code that's easy to understand and easy to maintain?
Anyway, your specific problem might relate to the session. In ShoppingCartsController you're defining #shopping_cart by looking up a session[:shopping_cart_id]. If multiple users (after logging out and logging in as someone else) are ending up with the same #shopping_cart.id, that must mean that their session values are the same. In the beginning of the relevant controller action, add a puts statement to give you extra info (it spits out to the console) about what the session values are:
puts session
If multiple users have the same session values, it likely means that the session isn't getting cleared properly when you log out and log in as someone else. You could test that by setting a different session variable, and seeing if that also persists from one user to another.
In general, adding lots of puts statements at the beginning of all relevant controller actions is a great (and super simple) way to get insight into what your application is thinking.
Hope that helps!

Session destroy not working in rails app?

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]

RoR - NoMethodError, undefined method

I have created an app with simple login authentication, it is actually a twitter clone. The user logs in and access the pages, etc.
But when the user posts something from there profile. It gives an error
NoMethodError in RibbitsController#create
undefined method `id=' for nil:NilClass
The error is around line 5:
class RibbitsController < ApplicationController
def create
#ribbit = Ribbit.create(user_ribbits)
#ribbit.userid = current_user.id
if #ribbit.save
redirect_to current_user
else
flash[:error] = "Problem!"
redirect_to current_user
end
end
private
def user_ribbits
params.require(:ribbit).permit(:content, :userid)
end
end
The request given to app:
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"dwVmjDNO4GOowphGFgChMDBxBfvka+M/xSUHvJMECzwxtv4NF6OuWtiaX74NLz91OwQJ9T9+wm7yMiPQ0BLpGA==",
"ribbit"=>{"content"=>"hi. test.\r\n"},
"commit"=>"Ribbit!"}
The sessions controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_username(params[:username])
if user && user.authenticate(params[:password])
session[:userid] = user.id
redirect_to rooturl, notice: "Logged in!"
else
flash[:error] = "Wrong Username or Password."
redirect_to root_url
end
end
def destroy
session[:userid] = nil
redirect_to root_url, notice: "Logged out."
end
end
The users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.create(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to #user, notice: "Thank you for signing up!"
else
render 'new'
end
end
def show
#user = User.find(params[:id])
#ribbit = Ribbit.new
end
private
def user_params
params.require(:user).permit(:name, :username, :email, :password, :password_confirmation, :avatar_url)
end
end
And the application controller
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
end
I would really appreciate it if you guys would help!
Thanks.
You're trying to assign current_user.idto #ribbit.userid without ensuring that current_user is set. 'current_user' would be set only if a user has been previously saved before.
Therefore, you need either to make sure that an authenticated user is trying to create a Ribbit, or if you consider the userid as a non mandatory field, you can simply change your line 5 by:
#ribbit.userid = current_user.id unless current_user.blank?
If you only want authenticated user to create Ribbits, then consider using a gem to handle authentication such as Devise. You could then use before_filter :authenticate_user! in your controller to make sure users are properly authenticated.

Setter method for current_user never being used

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

How to implement a "Remember Me" function in Rails 3?

What are the best practices to implement a "Remember Me" function in Rails 3 application ?
I store session information (session id + user id) in the database when user logs in, and I don't want to use any plugins at this moment.
Any pointers or code samples will be much appreciated.
You can just set the expiration on a signed cookie to accomplish this. (Signed cookies are tamper-proof just like the Rails-provided session cookie.)
class SessionsController < ApplicationController
def create
...
user = User.authenticate(params[:email_address], params[:password])
if params[:remember_me]
cookies.signed[:user_id] = { value: user.id, expires: 2.weeks.from_now }
else
# expires at the end of the browser session
cookies.signed[:user_id] = user.id
end
end
def destroy
cookies.delete :user_id
end
end
class ApplicationController < ActionController::Base
...
def current_user
User.find(cookies.signed[:user_id])
end
end
Railscasts has an episode on achieving this as well as well as a great HOWTO on implementing those features via BDD with RSpec and Capybara.
I store session information (session id + user id) in the database when user logs in
I believe that's one approach and the casts above does the same with cookies by issuing each User account a unique authentication token.
Have been reading the Rails tutorial book and it has an implementation for Remember Me
You can check for some hints (The implementation may be different from yours)
http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#sec:remember_me
This is how I implemented remember_me (the below snippet is from my example Rails app on authentication):
class SessionsController < ApplicationController
skip_before_filter :login_required, :only => [:new, :create]
def new
end
def create
#current_user = User.authenticate(params[:email], params[:password])
if #current_user
#current_user.track_on_login(request)
if params[:remember_me]
cookies[:remember_token] = { :value => #current_user.remember_token, :expires => 24.weeks.from_now }
else
cookies[:remember_token] = #current_user.remember_token
end
redirect_to dashboard_url, :notice => "Logged in successfully."
else
flash.now[:alert] = "Invalid login or password."
render 'new'
end
end
def destroy
current_user.track_on_logout
current_user.reset_remember_token_and_save # can't rely on the 'save_current_user_if_dirty' after_filter here
cookies.delete(:remember_token)
reset_session
redirect_to root_url, :notice => "You have been logged out."
end
end
Just an example without salt:
class ApplicationController < ActionController::Base
protected
def signin!(user_id)
return unless user_id
#current_user = User.find(user_id)
self.session_user_id = #current_user.id
self.permanent_user_id = #current_user.id if session[:accept_remember_me]
end
def signout!
self.session_user_id = nil
self.permanent_user_id = nil
session[:accept_remember_me] = nil
#current_user = nil
end
def remember_me
session[:accept_remember_me] = true
end
private
def permanent_user_id
cookies.signed[:permanent_user_id]
end
def permanent_user_id= value
cookies.permanent.signed[:permanent_user_id] = value
end
def session_user_id
session[:user_id]
end
def session_user_id= value
session[:user_id] = value
end
end

Resources