Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Devise Ajax login: 'sessions#create' only render 'create.js.erb' when it succeed

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:

  1. Display login form in a modal with remote: true Rails/UJS convention (OK);
  2. Create a custom sessions controller and point Devise to it (OK);
  3. Create a JS view file 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,

The environment:

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
like image 396
Edison Machado Avatar asked Mar 27 '14 13:03

Edison Machado


2 Answers

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
like image 185
Brad Werth Avatar answered Oct 14 '22 19:10

Brad Werth


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
like image 31
Andrey Avatar answered Oct 14 '22 19:10

Andrey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!