J'essaie de créer une Rails API pour une application iphone. Devise fonctionne très bien pour les connexions via l'interface Web, mais je dois pouvoir créer et détruire des sessions en utilisant REST API et je veux utiliser JSON au lieu d'avoir à faire un POST sur le contrôleur de sessions et avoir à analyser le HTML et gérer une redirection.
Je pensais pouvoir faire quelque chose comme ça:
class Api::V1::SessionsController < Devise::SessionsController
def create
super
end
def destroy
super
end
end
et dans config/routes.rb j'ai ajouté:
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
rake routes indique que les itinéraires sont correctement configurés:
api_v1_sessions POST /api/v1/sessions(.:format) {:action=>"create", :controller=>"api/v1/sessions"}
api_v1_session DELETE /api/v1/sessions/:id(.:format) {:action=>"destroy", :controller=>"api/v1/sessions"}
Quand je POST to/user/sessions tout fonctionne bien. J'obtiens du HTML et un 302.
Maintenant, si je POST to/api/v1/sessions j'obtiens:
Action inconnue AbstractController :: ActionNotFound
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST http://localhost:3000/api/v1/sessions -d "{'user' : { 'login' : 'test', 'password' : 'foobar'}}"
C'est ce qui a finalement fonctionné.
class Api::V1::SessionsController < Devise::SessionsController
def create
respond_to do |format|
format.html { super }
format.json {
warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
render :status => 200, :json => { :error => "Success" }
}
end
end
def destroy
super
end
end
Modifiez également routes.rb, n'oubliez pas que la commande est importante.
devise_for :users, :controllers => { :sessions => "api/v1/sessions" }
devise_scope :user do
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
end
resources :users
J'ai fini par utiliser une combinaison de la réponse de @ akshay et de la réponse de @ mm2001.
class Api::SessionsController < Devise::SessionsController
def create
warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
render :json => {:success => true}
end
def destroy
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
render :json => {}
end
def failure
render :json => {:success => false, :errors => ["Login Failed"]}
end
end
... et dans l'initialiseur de devise, je devais le faire pour obtenir la méthode #create pour utiliser mon :recall
gestionnaire
# config/initializers/devise.rb
config.navigational_formats = [:"*/*", "*/*", :html, :json]
C'est avec Devise 1.5.1 et Rails 3.1.
Une réponse récente ici: http://jessehowarth.com/devise a un peu plus de détails (par tilisation de Devise 1.3 pour authentifier les demandes de connexion JSON )
J'ai résolu le problème en créant un petit service qui distribue des jetons d'authentification. J'ai écrit un blog à ce sujet: http://matteomelani.wordpress.com/2011/10/17/authentication-for-mobile-devices/ . Vous pouvez également obtenir le code ici: https://github.com/matteomelani/Auth-Token-Service-Prototype .
Une solution alternative à la création/destruction de sessions consiste à utiliser token_authenticatable
module, puis mettez à jour les autres fonctions de votre API afin qu'elles prennent le jeton comme paramètre obligatoire. Il s'agit sans doute d'une conception plus ReSTful, car elle conserve l'apatridie (c'est-à-dire qu'il n'y a aucun état de session nulle part). Bien sûr, ce conseil vaut pour votre API JSON, mais je ne recommanderais pas la même chose pour votre interface HTML (les longues chaînes de jetons dans la barre d'URL de votre navigateur ne sont pas une jolie vue).
Voir ici pour un exemple.
Du rdoc pour #devise_scope de devise:
Définit la portée de l'appareil à utiliser dans le contrôleur. Si vous avez des itinéraires personnalisés, vous devez appeler cette méthode (également alias: as) afin de spécifier à quel contrôleur elle est ciblée.
as :user do
get "sign_in", :to => "devise/sessions#new"
end
Notez que vous ne pouvez pas avoir deux étendues mappées sur la même URL. Et n'oubliez pas que si vous essayez d'accéder à un contrôleur de devise sans spécifier de portée, cela générera une erreur ActionNotFound.
Il semble que vous ayez besoin de l'envelopper dans un bloc #as:
as :user do
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
end
Pas sûr que les formats de navigation doivent être utilisés, une API n'est pas vraiment ça ...
Par ceci article de blog il suffit d'ajouter
respond_to :html, :json
à vos contrôleurs.