Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Devise callback for "You are already signed in."?

When I revisit /users/sign_in after already being signed in, I see the flash You are already signed in. and the following in my logs..

Filter chain halted as :require_no_authentication rendered or redirected

..and I get redirected to /. I would like to call a callback and redirect differently depending on some condition.

This is similar in spirit to after_sign_up_path_for except it's more like "after trying sign in when already signed in".

like image 565
user664833 Avatar asked Mar 13 '14 07:03

user664833


People also ask

What is devise UID?

As Devise support OmniAuth integration by default. In order to do so it creates two extra column provider and uid where provider consist oAuth provider i.e facebook, google, linkedin etc. and uid will consist unique id of the user who logged in using oAuth.


2 Answers

Right now, there's no easy way to accomplish what you want. (Maybe a pull request is in order.)

The problem is that when the user is already authenticated, Devise calls the after_sign_in_path_for method.

This method is also called when the user logins normally, so even if you override this method, there's no way to distinguish between users who just logged in and those who were already logged in.

The only solution is to extend/override Devise's SessionsController:

class SessionsController < Devise::SessionsController

  private

  def require_no_authentication
    assert_is_devise_resource!
    return unless is_navigational_format?
    no_input = devise_mapping.no_input_strategies

    authenticated = if no_input.present?
      args = no_input.dup.push scope: resource_name
      warden.authenticate?(*args)
    else
      warden.authenticated?(resource_name)
    end

    if authenticated && resource = warden.user(resource_name)
      flash[:alert] = I18n.t("devise.failure.already_authenticated")
      redirect_to YOUR_PATH_HERE
    end
  end
end

Since this controller inherits from Devise's, when an action isn't defined in your controller that action will be processed by Devise's controller. So you only have to override that require_no_authentication method, which is called in a before_filter.

Finally, edit your routes file so this change takes effect:

# routes.rb
devise_for :users, :controllers => { :sessions => 'sessions' }
like image 170
Ashitaka Avatar answered Sep 21 '22 22:09

Ashitaka


The easiest way to make sure that the original functionality is preserved is to copy the entire method definition and change parts of it.

def require_no_authentication
  assert_is_devise_resource!
  return unless is_navigational_format?
  no_input = devise_mapping.no_input_strategies

  authenticated = if no_input.present?
    args = no_input.dup.push scope: resource_name
    warden.authenticate?(*args)
  else
    warden.authenticated?(resource_name)
  end

  if authenticated && resource = warden.user(resource_name)
    # CHANGE THE FOLLOWING LINES AS NEEDED  
    flash[:alert] = I18n.t("devise.failure.already_authenticated")
    redirect_to after_sign_in_path_for(resource)
  end
end
like image 40
jvnill Avatar answered Sep 21 '22 22:09

jvnill