6

In an earlier version of Devise (3.2) it was possible to access the user that had just signed out in the after_sign_out_path_for(resource) method and redirect according to any given attribute of that user.

In Devise 3.4 the method after_sign_out_path_for(resource_or_scope) just receives the class name as a symbol for the parameter resource_or_scope, i.e. :user in my case.

Is there another way of redirecting a given user after signing out based on the value of an attribute in the user model?

To clarify: I do not intend to create different user classes just for this to work.

McLibboc
  • 73
  • 1
  • 5

3 Answers3

4

I had the same need, and I took a different approach (since the act of logging out clears out your session) -- use an instance variable instead of session to store the user

class SessionsController < Devise::SessionsController
  def destroy
    @user = current_user
    super
  end
end

class ApplicationController < ActionController::Base
  def after_sign_out_path_for(resource)
    if @user.some_method?
       path_a
    else
       path_b
    end
  end
end

And, of course, in config/routes.rb

devise_for :users, controllers: {sessions: "sessions"}
Nathan Wallace
  • 2,154
  • 4
  • 23
  • 28
2

I had the exactly the same problem a while ago, and i couldn't found a way of doing it in a clean way. So to resolve that i just made a simple override to devise SessionsController in which i would save the desired attribute in session before Devise erased it:

class SessionsController < Devise::SessionsController
  def sign_out
    company_slug = session[:company_slug]
    super
    session[:company_slug] = company_slug
  end
end

And then on my after_sign_out_path_for i could do something like this:

def after_sign_out_path_for(resource_or_scope)
  if session[:company_slug] == 'something'
    something_path
  end
end

Of Course you don`t really need to override signout method, you could simply use

config.sign_out_all_scopes = false in devise.rb

Community
  • 1
  • 1
Guilherme
  • 79
  • 1
  • 11
0

Thanks for pointing me in the right direction. Your answer does need a bit of tweaking before it actually works.

The method to override actually is destroy (not sign_out). And when I called it with super it still didn't work, since the original session controller redirects to after_sign_out_path_for before session[:nosponsor] is set. So I had to override the whole method.

class SessionsController < Devise::SessionsController
  def destroy
    nosponsor = current_user && current_user.sponsor.blank?
    signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
    set_flash_message :notice, :signed_out if signed_out && is_flashing_format?
    yield if block_given?
    session[:nosponsor] = "true" if nosponsor
    respond_to do |format|
      format.all { head :no_content }
      format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) }
    end
  end
end

Additionally for this to work, there needs to be an entry in routes.rb

devise_for :users, :controllers =>  {:sessions =>  "sessions"}

I'd like to give you credit for your answer. So if you update it to incorporate these changes, I will accept it as the correct one. Thx again.

McLibboc
  • 73
  • 1
  • 5
  • I had just to overwrite the `after_sign_out_path_for` method. I didn't have to overwrite the `destroy` method and it worked. I'm using Devise 4.7.3. – Franchy Oct 04 '20 at 06:31