Devise token auth gem querying database twice for authenticating user - ruby-on-rails

I am using devise token auth gem in my Rails 5 API for authentication.
class V1::HuntsController < V1::MainController
include DeviseTokenAuth::Concerns::SetUserByToken
before_action :authenticate_user!
def index
end
end
But when I look at my logs, I see that there is two database queries to find the user. One from before_action :authenticate_user and the other from update_auth_header from after_action added by DeviseTokenAuth module.
Started POST "/v1/hunts" for 192.168.0.103 at 2016-12-07 15:41:03 +0530
Processing by V1::HuntsController#create as JSON
Parameters: {"title"=>"dddd", "clue"=>"dd", "hunt"=>{"title"=>"dddd", "clue"=>"dd"}}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."uid" = ? LIMIT ? [["uid", "raj#email.com"], ["LIMIT", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 15], ["LIMIT", 1]]
(0.1ms) begin transaction
(0.0ms) commit transaction
Completed 204 No Content in 102ms (ActiveRecord: 1.0ms)
Why is it firing another database query for user when current_user is already available? The database query doesnt seem to be cached also as it takes the same time to load.
I doubt if this is due to the default behavior in which token changes with each request. I have disabled this in my configuration.

Related

How do you authorize access to a page dealed by a controller without corresponding model with Cancancan?

The issue
A Spree admin controller without corresponding model, whose access trial redirect to an other page.
The corresponding attempt code:
module Spree
module Admin
class TutorialsController < Spree::Admin::BaseController
authorize_resource :class => false
def index
end
end
end
end
And in app/models/spree/ability_decorator.rb the following was added:
can :manage, :'tutorial'
can :manage, :'admin/tutorial'
can :manage, :'admin_tutorial'
can :manage, :'spree/admin/tutorial'
can :manage, :'spree_admin_tutorial'
But none of these authorizations will do the trick. Of course adding can :manage, :all at this place will make the page reachable as desired, so this is definitely solution close to that which is needed but less permissive that is looked for here. Even using skip_authorization_check in the controller won't do the trick, the request will be redirected to admin/products with these corresponding initial logs:
Started GET "/admin/tutorials" for 127.0.0.1 at 2020-04-30 17:11:28 +0200
Processing by Spree::Admin::TutorialsController#index as HTML
Spree::Preference Load (2.9ms) SELECT "spree_preferences".* FROM "spree_preferences" WHERE "spree_preferences"."key" = $1 LIMIT $2 [["key", "spree/backend_configuration/locale"], ["LIMI
T", 1]]
↳ /home/psychoslave/.rvm/gems/ruby-2.5.1#project/bundler/gems/spree_i18n-a03ecad00a1e/lib/spree_i18n/controller_locale_helper.rb:21
Spree::User Load (3.2ms) SELECT "spree_users".* FROM "spree_users" WHERE "spree_users"."deleted_at" IS NULL AND "spree_users"."id" = $1 ORDER BY "spree_users"."id" ASC LIMIT $2 [["id",
194], ["LIMIT", 1]]
↳ /home/psychoslave/.rvm/gems/ruby-2.5.1#project/gems/activerecord-5.2.2/lib/active_record/log_subscriber.rb:98
Spree::Role Load (3.4ms) SELECT "spree_roles".* FROM "spree_roles" INNER JOIN "spree_role_users" ON "spree_roles"."id" = "spree_role_users"."role_id" WHERE "spree_role_users"."user_id" =
$1 [["user_id", 194]]
↳ /home/psychoslave/.rvm/gems/ruby-2.5.1#project/gems/activerecord-5.2.2/lib/active_record/log_subscriber.rb:98
Spree::Producer Load (2.6ms) SELECT "spree_producers".* FROM "spree_producers" WHERE "spree_producers"."id" = $1 LIMIT $2 [["id", 16], ["LIMIT", 1]]
↳ app/models/spree/ability_decorator.rb:123
Redirected to http://localhost:5000/forbidden
Completed 302 Found in 80ms (ActiveRecord: 41.4ms)
And after a few other redirections, the request lead to the previously stated path.
Pertaining related resources
Adding a Controller without corresponding model while using cancancan proposes a solution which unfortunately didn't work in this case.
How to authorize namespace, model-less controllers using CanCanCan? suggest the use of skip_authorization_check
There was no need for special ability after all in this case. The Spree::BaseController sets the correct permissions to grant the aimed access, unlike Spree::Admin::BaseController. To keep the CSS style consistent, an explicit layout statement is required.
module Spree
module Admin
class TutorialsController < Spree::BaseController
layout 'spree/layouts/admin'
def index; end
end
end
end

Devise - sign_in() not working rails 5.2.0

Created new ruby app
in my controller im trying to sign in a user like so
email = params[:email]
password = params[:password]
user = User.authenticate(email, password)
if user
sign_in(user)
redirect_to root_path
else
render json: {success: false}
end
The user is going into sign_in
console is printing:
Processing by AccountController#sign_in_user as */*
Parameters: {"password"=>"[FILTERED]", "email"=>"email#live.com", "subdomain"=>"app"}
User Load (1.9ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["email", "email#live.com"], ["LIMIT", 1]]
↳ app/models/user.rb:9
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 2], ["LIMIT", 1]]
↳ app/controllers/account_controller.rb:11
Redirected to http://app.lvh.me:3000/
Completed 200 OK in 131ms (ActiveRecord: 2.4ms)
It then redirects to my root path for authenticated users and gives me a 401
Started GET "/" for 127.0.0.1 at 2018-04-30 21:53:39 -0400
Processing by DashboardController#index as HTML
Parameters: {"subdomain"=>"app"}
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms)
In the DB the user's current_sign_in, last_sign_in, ect.. are being updated
I've done this numerous times, i'm not sure why its not working, any ideas?
Well after an hour of going crazy
i had a random line in my routes
devise_for :users
with no end doing nothing and it was causing this issue.
after removing that everything is fine.

Custom redirect based on user role in rails 5 with devise

Its been some time since I've worked with rails and I am jumping into a "project" for a company I work for..
Essentially what I am trying to do is redirect a user who logs in to the app to a specific page upon login..
For example an admin user will be redirected to an admin dashboard, an owner will be redirected to an owner dashboard and a driver to a driver dashboard..
Ive done this in the past using a single view and then filling it with elseif statements. But I found that to make my code look clunky and slow the app down.
I cant seem to find any docs (probably because I've been out of the game so long) on how to redirect to a specific url based on a user role.. Is this even possible? if so would someone be willing to share some resources as I am reaally struggling in this department.
Thanks in advance!
EDIT 1: Implemented ApplicationController method to find user role and redirect to appropriate page.
so I have added a few lines of code to my ApplicationController
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def after_sign_in_path_for(resource)
if current_user.role == "dispatch"
dashboard_dispatch_path
else
root_path
end
end
end
when I try to load the page, the url in the browser changes to the proper url, however I get the following error:
the stack trace from rails server:
Started POST "/users/sign_in" for 127.0.0.1 at 2018-04-01 12:10:58 -0600
Processing by Devise::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"LJSAbgb3spFs0kEgFMYa40m2TZmZvH7weq53ciuGZAO07SUBgTHdxYTH0+MjRuYZIi+9++zIjnJP2rllVws5DA==", "user"=>{"email"=>"swixxxx#xxxxxltd.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["email", "swixxxx#xxxxxxltd.com"], ["LIMIT", 1]]
(0.2ms) BEGIN
SQL (0.6ms) UPDATE "users" SET "current_sign_in_at" = $1, "sign_in_count" = $2, "updated_at" = $3 WHERE "users"."id" = $4 [["current_sign_in_at", "2018-04-01 18:10:58.835548"], ["sign_in_count", 2], ["updated_at", "2018-04-01 18:10:58.836544"], ["id", 2]]
(1.0ms) COMMIT
Redirected to http://localhost:3000/dashboard/dispatch
Completed 302 Found in 150ms (ActiveRecord: 2.6ms)
Started GET "/dashboard/dispatch" for 127.0.0.1 at 2018-04-01 12:10:58 -0600
ArgumentError - wrong number of arguments (given 3, expected 0):
app/controllers/dashboard_controller.rb:5:in `dispatch'
Started POST "/__better_errors/cda7f553a5c61c4b/variables" for 127.0.0.1 at 2018-04-01 12:10:58 -0600
EDIT 2: adds Controller Code:
class DashboardController < ApplicationController
def admin
end
def dispatch
end
def owner
end
def driver
end
def client
end
def guest
end
end

POST "/admin/users/26/approve_vip" not working

I want to approve the user to be vip,but when I press the button.The page refreshed but nothing changed.The log in terminal is
Started POST "/admin/users/26/approve_vip" for ::1 at 2016-12-12 16:33:22 +0800
Processing by Admin::UsersController#approve_vip as HTML
Parameters: {"authenticity_token"=>"qYrbaVH/cssY3VBYLw6Hd4wXl42Zz8OqkdHGGoITEeeWtbJ4ZOLOmJF/Jmpx70s9aaL5Yr0vFhqNV9kGHtILpA==", "user_id"=>"26"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 4], ["LIMIT", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 26], ["LIMIT", 1]]
SQL (1.4ms) UPDATE "users" SET "is_vip" = 't' WHERE "users"."id" = ? [["id", 26]]
(0.0ms) begin transaction
(0.0ms) commit transaction
DEPRECATION WARNING: `redirect_to :back` is deprecated and will be removed from Rails 5.1. Please use `redirect_back(fallback_location: fallback_location)` where `fallback_location` represents the location to use if the request has no HTTP referer information. (called from approve_vip at /Users/a1/JDDstore/app/controllers/admin/users_controller.rb:26)
Redirected to http://localhost:3000/admin/users
Completed 302 Found in 6ms (ActiveRecord: 1.7ms)
Started POST "/admin/users/26/approve_vip" for ::1 at 2016-12-12 15:41:47 +0800
Processing by Admin::UsersController#approve_vip as HTML
Parameters: {"authenticity_token"=>"uYc9hdEZaYCgfhdmYK3XnyK2lcraPpHWfuXcQ5cRtLyGuFSU5ATV0yncYVQ+TBvVxwP7Jf7eRGZiY8NfC9Cu/w==", "user_id"=>"26"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 4], ["LIMIT", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 26], ["LIMIT", 1]]
(0.0ms) begin transaction
(0.0ms) commit transaction
DEPRECATION WARNING: `redirect_to :back` is deprecated and will be removed from Rails 5.1. Please use `redirect_back(fallback_location: fallback_location)` where `fallback_location` represents the location to use if the request has no HTTP referer information. (called from approve_vip at /Users/a1/JDDstore/app/controllers/admin/users_controller.rb:26)
Redirected to http://localhost:3000/admin/users
Completed 302 Found in 4ms (ActiveRecord: 0.3ms)
And the code in controller is
def approve_vip
#user = User.find(params[:user_id])
#user.is_vip=true
#user.save
redirect_to :back
end
Can you tell me why it not change the role?
If you want to know more informatian, please let me know. Thank you very much for helping me.
It looks you have some model callback (may be before_save) which is restricting to update the records.
You can use update_column or update_columns to bypass the callbacks/validations and directly make a update query to your db.
def approve_vip
#user = User.find(params[:user_id])
#user.update_columns(is_vip: true)
redirect_to :back
end
You need to read error's message. Probably the user's validation is failed.
def approv!
update_attributes!(is_vip: true)
end
This code give you exception with the error's message.

Logout from ActiveAdmin destroy other sessions

I am using devise with activeadmin and one other model.
If I open both interfaces on browser and logout from one it will also destroy other sessions.
Started GET "/admin/logout" for 127.0.0.1 at 2015-11-03 19:45:25 +0500
Processing by ActiveAdmin::Devise::SessionsController#destroy as HTML
Parameters: {"authenticity_token"=>"6rqzYcjQNgm8sOcAy2ItHvqGWTYyUBEK2tE+hJi8Ti0E25qJLR+vdA9W++HHtFaD3CpBtnNAn6xbhS6mr8YLTQ=="}
Teacher Load (30.4ms) SELECT `teachers`.* FROM `teachers` WHERE `teachers`.`id` = ? ORDER BY `teachers`.`id` ASC LIMIT 1 [["id", 1]]
AdminUser Load (0.2ms) SELECT `admin_users`.* FROM `admin_users` WHERE `admin_users`.`id` = ? ORDER BY `admin_users`.`id` ASC LIMIT 1 [["id", 1]]
SQL (0.1ms) BEGIN
(0.0ms) COMMIT
SQL (0.0ms) BEGIN
(0.0ms) COMMIT
By default when Devise::SessionsController#destroy is invoked it will destroy the sessions from all scopes. This is configurable via sign_out_all_scopes. So to disable it, set it to false:
# config/initializers/devise.rb
config.sign_out_all_scopes = false

Resources