Devise redirect after login fail

Ruby on-RailsRedirectLoginDevise

Ruby on-Rails Problem Overview


All the questions I've found are related for a successful login with the helper after_sign_in_path_for(resource)

I have a login form in the index of the site, and when the login fails it redirects to "users/sign_in"

But how can I redirect to my "site#index" when the login fails?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

  1. Create a custom_failure.rb in your lib directory, with:

     class CustomFailure < Devise::FailureApp
       def redirect_url
         your_path
       end
    
       def respond
         if http_auth?
           http_auth
         else
           redirect
         end
       end
     end
    
  2. In you Devise initializer, include:

       config.warden do |manager|
         manager.failure_app = CustomFailure
       end
    
  3. Make sure Rails is loadin your lib files, in your application.rb :

     config.autoload_paths += %W(#{config.root}/lib)
    

Don't forget to restart your server.

I don't think there's an easier way to do this. Good luck.

Solution 2 - Ruby on-Rails

If you use your own SessionsController, you can re-assign the :recall value of auth_options to recall the controller#method you want before running warden.authenticate!(auth_options), for example:

in app/controllers/users/sessions_controller.rb

class Users::SessionsController < Devise::SessionsController
  #...
  def create
    #...
    auth_options = { :recall => 'site#index', :scope => :user }
    resource = warden.authenticate!(auth_options)
    #...
  end
  #...
end

With this way, you don't need to create the customized FailureApp and modify the configs.

Solution 3 - Ruby on-Rails

This is what happens with devise 3.1.0

Started POST "/users/sign_in"
Processing by Devise::SessionsController#create
Completed 401 Unauthorized
Processing by Devise::SessionsController#new

new gets called because of the auth_options defined at the end of gems/devise-3.1.0/app/controllers/devise/sessions_controller.rb

You should redefine the auth_options used in the create action. I copied the controller in app/controllers/devise/sessions_controller.rb of my Rails application and replaced the auth_options method like this

def auth_options
  { :scope => resource_name, :recall => "Home#new" }
end

It does the trick, but the url is still /users/sign_in

I'll try to fix that as well.

Solution 4 - Ruby on-Rails

Solution 5 - Ruby on-Rails

Elaborating on Marcao's answer, I highly recommend placing some debugger in your CustomFailure respond method in order to better understand what is going on.

Class CustomFailure < Devise::FailureApp
  def respond
    binding.pry
    super
  end
end

If you look at the FailureApp Devise Source Code for the respond method it is super easy to understand what is going on.

def respond
  if http_auth?
    http_auth
  elsif warden_options[:recall]
    recall
  else
    redirect
  end
end

So for example in order to return a redirect_url you would want to make sure that your respond code conditionals eventually return redirect.

However if you want to maybe return a standard 401 status as defined in the http_auth method, you want to verify that your respond method code returns http_auth.

Thus it is worth your while to look into the definition of the http_auth? In particular, note the: request.xhr? method, which will return 0 for json requests (recall that 0 actually evaluates to true in ruby)

def http_auth?
  if request.xhr?
    Devise.http_authenticatable_on_xhr
  else
    !(request_format && is_navigational_format?)
  end
end

And maybe check your initializers/devise file for config.http_authenticatable_on_xhr or config.navigational_formats in order to control the response that you want. This configuration can really affect what Devise returns and can often lead to unexpected behavior due to what it does here under the hood.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJuanjoView Question on Stackoverflow
Solution 1 - Ruby on-RailsMarco AntonioView Answer on Stackoverflow
Solution 2 - Ruby on-RailsSibevin WangView Answer on Stackoverflow
Solution 3 - Ruby on-RailspmontrasioView Answer on Stackoverflow
Solution 4 - Ruby on-RailsMikeHView Answer on Stackoverflow
Solution 5 - Ruby on-RailsAmitFView Answer on Stackoverflow