sRails 5 Devise after_sign_in_path - ruby-on-rails

I have a Rails 5 app with Devise. Each user has a role_id where they are assigned a role upon creation. I'm trying to use the after_sign_in_path_for method that Devise gives to redirect to a specific page on login based on the role.
Below is what I have so far, but it doesn't work when trying to sign out a disabled user.
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
case resource.role_id
when Role.find_by(name: "admin").id
root_path
when Role.find_by(name: "disabled").id
destroy_user_session_path
else
super
end
end
end
I'm able to sign in when I'm an admin user and it redirects. But if I try to sign in as a user whose role is disabled, it tries to tear down the session then raises an exception of No route matches [GET] "/users/sign_out". I know the method destroy_user_session_path expects a delete method but how can I pass this in the application controller?
What am I doing wrong here?
Update
I tried the sign_out(resource) as suggested in the first answer, and it raises an exception undefined methodto_model' for true:TrueClassin mymy_sessions_controller.rb` which I use to override the create method to set a login token and limit concurrent sessions. Here is the controller.
class MySessionsController < Devise::SessionsController
skip_before_action :check_concurrent_session
def create
super
set_login_token
end
private
def set_login_token
token = Devise.friendly_token
session[:token] = token
current_user.login_token = token
current_user.save(validate: false)
end
end

You can check roles inside MySessionsController#create and prevent logging if the role not valid instead of allowing user to login then logout
def create
unless current_user.role_id == Role.find_by(name: "disabled").id
super set_login_token
else
redirect_to new_user_session_path, alert: "You can't log in"
end
end
You can also use active_for_authentication? and inactive_message methods in user model to prevent him from login. in /app/models/user.rb:
def active_for_authentication?
super and self.role_id != Role.find_by(name: "disabled").id
end
def inactive_message
"You can't log in"
end

destroy_user_session_path is making [GET] "/users/sign_out" request.
You can use sign_out or reset_session function to delete session directly.
Hope this answer works for you.

Use devise's sign_out(resource) method instead of destroy_user_session_path. This method will destroy the user session.

Related

How can I prevent user access?

I have a view that to access you must log in ,my users table I have a field called kind.
I am using gem devise
enum kind: {
admin: 0,
customer: 1
}
add this in application_controller
def user_can_access(resource)
if current_user
if resource.is_admin?
root_path
else
sign_out current_user
new_user_session_path
end
end
end
user.rb
def is_admin?
self.admin?
end
That is my attempt to solve it, but it is wrong since I want the user that I do not want to access the view to not login.
In my method, the user who does not have access logs in but then I log him out, which I think is wrong
How can I prevent client access?
note:I will only have a page for the administrator, the other users will not have a view to access.
You can check the cancancan gem for authorization features or you can write yours then include a before action to check if the current_user is authorized before rendering the view.
e.g
class MyPage < ApplicationController
before_action :is_authorized?
def show_my_page
#foo == bar
end
private
def is_authorized?
return true if current_user.kind == admin
redirect_to root_path, notice: "You are not allowed to access this page"
end
end

Devise force logout for some users from Rails App

Is it possible to force logout for SOME of the users through Devise.
In my setup, I am using rails 4.1.15 with Devise 1.5.4. Sessions are persisted in db and there is no direct mapping with user ids. Is there a Devise way to logout against some of the users NOT ALL.
I tried resetting password as a proxy which logs out immediately but not always.
user_obj.update_attributes(:password => "some_random_string")
I can propose you next solution.
Add a new column for admin that called force_logout:boolean
In any your controller add a new action to set force_logout to true. Ex.:
# in admins_controller.rb
def force_logout
admin = Admin.find(params[:id])
admin.update_column(:force_logout, true)
redirect_to :back
end
In application_controller.rb add before_action to logout user if force_logout is true
before_action :check_force_logout
def check_force_logout
if current_user && current_user.force_logout?
current_user.update_column(:force_logout, false)
sign_out(current_user)
end
end
Too you need reset force_logout column after admin will be signed in. Usually you can do it session_controller.rb in action create.
Time to exhume this one. The only way I was able to solve this issue was by accessing the sessions. It is slow but it works.
def sign_out_different_user
#user = User.find(params[:id])
sessions = ActiveRecord::SessionStore::Session.where("updated_at > ?", Time.now - 480.minutes).all
sessions.each do |s|
if s.data['user_email'] == #user.email
s.delete and return
end
end
end
I needed to change the session expiration on the user object for my purposes, so I added this into the method, as well. YMMV
#user.session_expires_at = Time.now
#user.save

How can I make specific user(not current_user) sign out on rails-devise website?

I want to know how I can make specific user(not current_user) sign out.
I saw this http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Controllers/SignInOut#sign_out-instance_method and maked this code.
def kick_admin
user = User.find params[:user_id]
user.admin = false
user.save
sign_out user #want to kick him.
end
But it does not make that user sign out but make me(current_user) signed out.
What is the right way to use the sign_out method?
I checked this answer(Sign out specific user with Devise in Rails) but it was not helpful.
One way you could do this is create a new attribute in the User table, call it force_sign_out.
def kick_admin
user = User.find params[:user_id]
user.update_attributes(admin: false, force_sign_out: true)
end
And have a before action in ApplicatonController so that if the user attempts any activity he's signed out
class ApplicationController < ActionController::Base
before_action :check_if_force_sign_out
def check_if_force_sign_out
return unless current_user.force_sign_out
current_user.update_attributes(force_sign_out: false) # reset for non-admin log in
sign_out
redirect_to root_path
end
end

Rails devise redirect after confirming email

I want to redirect to the rooth path after a users confirms his email by clicking on the activation link. The devise wiki says to implement the following method in the registrations controller:
def after_inactive_sign_up_path_for(resource_or_scope)
session["user_return_to"] || root_path
end
But it doesnt get picked up and keeps directing my to the following url:
http://localhost:3000/users/sign_in
How can i override this behaviour of devise?
def after_inactive_sign_up_path_for(resource_or_scope)
root_path
end
Anonymousxxx posted the answer in a comment. The method is supposed to be in the confirmationscontroller.
module Users
class ConfirmationsController < Devise::ConfirmationsController
protected
def after_confirmation_path_for(_, _)
root_path
end
end
end

undefined method `is_admin?' for nil:NilClass :(

I want to restrict the access to my pannel admin (gem active_admin) for admin only.
That's my code
class ApplicationController < ActionController::Base
def authenticate_admin!
unless current_user.is_admin?
flash[:error] = "Access denied"
redirect_to root_path
end
end
and the problem is : undefined method `is_admin?' for nil:NilClass
there is a boolean admin (0 false, true 1) in my DB
I've to define my is_admin?, but i try and he is never found. So where do i have to do that ?
Thx for your help
The issue is in your error message. nil doesn't have the method 'is_admin?'. This means that your current user variable isn't being set. You need to redirect users who are not logged-in to a screen where they can do so. Then direct them either through this authenticate_admin! function either first to redirect all user who are admin to the /admin path or simply push all users to your home page allowing them to click an admin link.
It could be that current_user is being set correctly, but this method is being called when there is no logged in user.
You should use this method in conjunction with another filter which requires the user to be logged in, ie which requires current_user to be defined. This is typically called require_user
Eg, in your application controller (so it gets inherited by all controllers)
before_filter :require_user
protected
def require_user
unless current_user
redirect_to "/" and return
end
end
You then make exceptions for the non-logged-in actions, with skip_before_filter.
Now, you can add authenticate_admin! as a before filter in your admin controller: it will only ever by called when require_user has already been passed, so it should be safe.
Add try: <% if current_user.try(:is_admin?) %>
Try simply add before_action :authenticate_user! (if your user called 'user') before :authentificate_admin! method. After this change your app will redirect non-logged users to login form first and only after that will ask your user 'is he admin?'.

Resources