Skip to content

Instantly share code, notes, and snippets.

@codespore
Created August 31, 2012 23:49
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save codespore/3561310 to your computer and use it in GitHub Desktop.
Save codespore/3561310 to your computer and use it in GitHub Desktop.
Sench Touch with Rails
References:
http://blog.carbonfive.com/2012/02/27/supporting-cross-domain-ajax-in-rails-using-jsonp-and-cors/
https://github.com/cyu/rack-cors
http://nelm.io/blog/2011/11/cors-with-sencha-touch/
http://jessehowarth.com/2011/04/27/ajax-login-with-devise
=============================================================================================================
GEMFILE
=============================================================================================================
gem 'rack-cors', :require => 'rack/cors'
=============================================================================================================
config/application.rb
=============================================================================================================
# Ensure Rack::Cors to run before Warden::Manager used by Devise
config.middleware.insert_before Warden::Manager, Rack::Cors do
allow do
origins '*'
resource '*',
:headers => :any,
:methods => [:get, :post, :options]
end
end
=============================================================================================================
config/initializers/devise.rb
=============================================================================================================
config.http_authenticatable_on_xhr = false
config.navigational_formats = ["*/*", :html, :json]
=============================================================================================================
Custom Devise Sessions Controller: app/controllers/sessions_controller.rb
=============================================================================================================
class SessionsController < Devise::SessionsController
def create
if request.xhr?
resource = warden.authenticate!(:scope => resource_name, :recall => "sessions#failure")
return sign_in_and_redirect(resource_name, resource)
else
super
end
end
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
return render :json => {:success => true, :redirect => stored_location_for(scope) ||
after_sign_in_path_for(resource)}
end
def failure
return render:json => {:success => false, :errors => ["Login failed."]}
end
end
=============================================================================================================
Custom Devise Sessions Controller: config/routes.rb
=============================================================================================================
devise_for :users, :controllers => {:sessions => 'sessions'}
@mcka1n
Copy link

mcka1n commented Jun 10, 2014

It works like a charm!!

I didn't have to override the SessionsController thought.

@daraosn
Copy link

daraosn commented Dec 10, 2015

I'm not using Sencha, but I debugged into Devise and found out that the SessionsController could be simplified for some cases where you don't need the redirect, because Devise::SessionsController#create will trigger #new on failure as you can see in the source code:

class Devise::SessionsController < ApplicationController
# ...
  def create
    resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
    set_flash_message(:notice, :signed_in) if is_navigational_format?
    sign_in(resource_name, resource)
    respond_with resource, :location => after_sign_in_path_for(resource)
  end

This is my proposed solution (for some reason the request was not setting xhr = true, so I had to check the request format too):

class SessionsController < Devise::SessionsController
  def new
    return super if !(request.xhr? or request.format == :json)
    render json: { success: false, errors: ["Login failed"] }, status: :unauthorized
  end
end

The logic behind is that you don't need to render sessions#new on an API request, because you're supposed to have a registration endpoint in your API, therefore you can render unauthorized access. Hope it helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment