My goal is to implement an Ajax login solution with Devise with the minimal change of patterns. I already reached it partially, but there is one problem with the failure callback. Let me explain the scenario:
remote: true Rails/UJS convention (OK);sessions controller and point Devise to it (OK);create.js.erb to respond for sessions#create action (PROBLEM);The problem: My create.js.erb only contains an alert("Test ok"). When I submit the sessions#new form with the correct credentials the file create.js.erb is executed, the alert is shown. But with wrong credentials it doesn't, returning 401 Unauthorized status and create.js.erb is ignored.
Maybe someone know a quick trick to make create.js.erb run when login fail. This way I don't need to create a standalone Ajax script or change entire sessions controller.
Thank you,
VERSIONS:
Rails 4.0.2
Devise 3.2.2
Custom sessions controller:
class Website::SessionsController < ::Devise::SessionsController
respond_to :js # without it neither on success create.js.erb runs
layout false # action `new` pure html which is rendered in a modal box
end
sessions/create.js.erb
alert("Test ok");
Server log when login fails:
Started POST "/users/sign_in" for 127.0.0.1 at 2014-03-27 09:59:47 -0300
Processing by Website::SessionsController#create as JS
Parameters: {"utf8"=>"✓", "user"=>{"email"=>"", "password"=>"[FILTERED]"}, "commit"=>"Fazer login"}
Completed 401 Unauthorized in 1ms
When successful, the create.js.erb template is rendered.
When unsuccessful, for any reason, the new.js.erb template is rendered.
The easiest way to deal with this, is to simply add new.js.erb. This involves the least amount of modification to the devise controller.
It may be worth noting that I had to make the following adjustments, in addition to adding remote: true to the form, to even get the create.js.erb to render.
config/initializers/devise:
# If http headers should be returned for AJAX requests. True by default.
config.http_authenticatable_on_xhr = false
config/routes.rb:
devise_for :users, controllers: { sessions: 'users/sessions' }
controllers/users/sessions_controller.rb:
class Users::SessionsController < Devise::SessionsController
respond_to :html, :js
end
Problem occurs because of:
warden.authenticate!(...)
It raise the exception and don't render your view after.
You should to override SessionsController#create action for your own behavior. For example like this:
def create
self.resource = warden.authenticate(auth_options)
if resource && resource.active_for_authentication?
...
sign_in(resource_name, resource)
...
else
...
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With