nuT707
nuT707

Reputation: 1573

Devise multiple pathes for one model

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

Answers (3)

nuT707
nuT707

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

Guillermo Aguirre
Guillermo Aguirre

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

Mark
Mark

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

Related Questions