Devise - Sign In with Ajax Devise - Sign In with Ajax ajax ajax

Devise - Sign In with Ajax


1. Generate Devise controllers so we can modify it

rails g devise:controllers

enter image description here

Now we have all controllers in the app/controllers/[model] directory

2. Edit routes.rb

Let's set Devise to use our modified SessionsController

First add this code (of course change :users to your devise model) into config/routes.rb

devise_for :users, controllers: {  sessions: 'users/sessions'}

3. Modify sessions_controller.rb

enter image description here

Find the create method and change it to

def create  resource = User.find_for_database_authentication(email: params[:user][:email])  return invalid_login_attempt unless resource  if resource.valid_password?(params[:user][:password])    sign_in :user, resource    return render nothing: true  end  invalid_login_attempt end

Create new method after protected

def invalid_login_attempt  set_flash_message(:alert, :invalid)  render json: flash[:alert], status: 401end

4. devise.rb

Insert this into config/initializers/devise.rb

config.http_authenticatable_on_xhr = falseconfig.navigational_formats = ["*/*", :html, :json]

5. Invalid email or password message

Insert a new message into config/locales/devise.en.yml under the sessions

invalid: "Invalid email or password."

sessions

6. View

= form_for resource, url: session_path(:user), remote: true do |f|  = f.text_field :email  = f.password_field :password  = f.label :remember_me do    Remember me    = f.check_box :remember_me  = f.submit value: 'Sign in':javascript  $(document).ready(function() {    //form id    $('#new_user')    .bind('ajax:success', function(evt, data, status, xhr) {      //function called on status: 200 (for ex.)      console.log('success');    })    .bind("ajax:error", function(evt, xhr, status, error) {      //function called on status: 401 or 500 (for ex.)      console.log(xhr.responseText);    });  });

Important thing remote: true

The reason why I am using status 200 or 401 unlike {status: 'true'} is less data size, so it is much faster and cleaner.

Explanation

On signing in, you get these data in params

action: "create"commit: "Sign in"controller: "users/sessions"user: {  email: "test@test.cz"  password: "123"  remember_me: "0"}utf8: "✓"

Before signing, you need to authorize the user.

resource = User.find_for_database_authentication(email: params[:user][:email])

User.find_for_database_authentication

If user is found, resource will be filled with something like

created_at: "2015-05-29T12:48:04.000Z"email: "test@test.cz"id: 1updated_at: "2015-06-13T19:56:54.000Z"

Otherwise will be

null

If the user is authenticated, we are about to validate his password

if resource.valid_password?(params[:user][:password])

And finally sign in

sign_in :user, resource

Sources

SessionsController

Helped meAndreas Lyngstad