Reputation: 1573
I want to have two different routes for devise:
routes.rb
devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout' }
namespace :api, defaults: { format: :json } do
devise_for :users,
path: '',
defaults: { format: :json },
path_names: {
sign_in: 'login',
sign_out: 'logout',
},
controllers: { sessions: 'api/sessions' }
end
rails routes | grep sessio
new_user_session GET /login(.:format) devise/sessions#new
user_session POST /login(.:format) devise/sessions#create
destroy_user_session DELETE /logout(.:format) devise/sessions#destroy
new_api_user_session GET /api/login(.:format) api/sessions#new {:format=>:json}
api_user_session POST /api/login(.:format) api/sessions#create {:format=>:json}
destroy_api_user_session DELETE /api/logout(.:format) api/sessions#destroy {:format=>:json}
api/sessions_controller.rb
class Api::SessionsController < Devise::SessionsController
skip_before_action :verify_authenticity_token
skip_before_action :authenticate_user!
respond_to :json
private
def respond_with(resource, _opts = {})
render json: resource
end
def respond_to_on_destroy
head :no_content
end
end
That code looks fine for me, but when i try to send POST-request to my localhost:3000/api/login with auth credentials it returns error:
{"error":"You need to sign in or sign up before continuing."}
If i comment out my default devise routes and move api routes from api namespace everything works fine, post-request return me json with resource: routes.rb
#devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout' }
devise_for :users,
path: 'api',
defaults: { format: :json },
path_names: {
sign_in: 'login',
sign_out: 'logout',
},
controllers: { sessions: 'api/sessions' }
namespace :api, defaults: { format: :json } do
...
end
Why that happened? What i'm missing?
Upvotes: 2
Views: 2456
Reputation: 1573
My answer:
routes.rb
devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout' }
devise_scope :user do
post 'api/login', to: 'api/sessions#create', as: 'api_login', defaults: {format: :json}
get 'api/logout', to: 'api/sessions#destroy', as: 'api_logout', defaults: {format: :json}
end
It's similiar with Guilermo Aguirre answer.
Upvotes: 1
Reputation: 841
Having this in my routes:
Rails.application.routes.draw do
devise_for :users,
path: '',
path_names: {
sign_in: 'login',
sign_out: 'logout'
}
namespace :api, defaults: { format: :json } do
namespace :users do
devise_scope :user do
post 'login', to: 'sessions#create', defaults: { format: :json }
end
end
end
end
rails routes
outputs:
Prefix Verb URI Pattern Controller#Action
new_user_session GET /login(.:format) devise/sessions#new
user_session POST /login(.:format) devise/sessions#create
destroy_user_session DELETE /logout(.:format) devise/sessions#destroy
api_v1_users_login POST /api/v1/users/login(.:format) api/v1/users/sessions#create {:format=>:json}
Making the POST request to http://localhost:3000/api/v1/users/login
works as expected
And now accessing http://localhost:3000/login
redirects to the default devise login page, and login works as it should. The problem was you can't have the same devise_for
twice. You can have devise_for :users
and devise_for :admin_users
but not twice for the same, in this case :users
.
Upvotes: 7
Reputation: 6455
I think in your initial route definition, you're already in the API namespace, so when you define your controller, you don't need
'api/sessions'
But just
'sessions'
I think this will make the request hit the correct controller, which means your authenticate_admin! method won't fire, which it is at the moment, resulting in your auth issue.
Upvotes: 0