Devise redirect after login fail
Ruby on-RailsRedirectLoginDeviseRuby 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
-
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
-
In you Devise initializer, include:
config.warden do |manager| manager.failure_app = CustomFailure end
-
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
You can change the default sign_in path.
Check out https://github.com/plataformatec/devise/wiki/How-To:-Change-the-default-sign_in-and-sign_out-routes
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.