Rails Sign in using devise to authenticate from two db tables

836 views Asked by At

I have 2 database tables namely coreteam and user. Both the models are configured with devise. For now to sign in for core team my API is: localhost:3000/api/v1/core_teams/sign_in with following request data.

{ 
  "core_team": {
    "email": "[email protected]",
    "password": "Password21"
  }
}

And the API for users to sign in is: localhost:3000//api/v1/users/sign_in with the following request data.

{
  "user": {
    "email": "[email protected]",
    "password": "Password20"
  }
}

And following is my routes.rb file

 Rails.application.routes.draw do

 root to: 'users#index'

scope 'api/v1', defaults: { format: :json } do
 devise_for :core_teams, controllers: {
   sessions: 'api/v1/sessions',
   passwords: 'api/v1/passwords'
  }

 devise_for :users, controllers: {
   sessions: 'api/v1/sessions',
   invitations: 'api/v1/invitations',
   passwords: 'api/v1/passwords',
   registrations: 'api/v1/registrations'
  }
  end
end

And I am using devise sessionscontroller to login. Only difference is the way I am rendering the data.

My sessions_controller.rb is as follows:

module Api
 module V1
  class SessionsController < Devise::SessionsController
   private

    def respond_with(resource, _opts = {})
      render json: resource
    end

    def respond_to_on_destroy
      head :no_content
    end

   end
  end
 end

Now my aim is to have only one API call to sign in using the same type of requests data. Reason to have two different user table is my app is kind of multi-tenanted and core team is outside of tenant and users are inside tenant.

CoreTeam and Tenant Architecture

1

There are 1 answers

0
PGill On BEST ANSWER

Try this

routes

post "/api/v1/sign_in" => "api/v1/sessions#create"

devise_for :users, ...
devise_for :core_teams, ...

api/v1/sessions_controller.rb

module Api
  module V1
    class SessionsController < Devise::SessionsController
      before_action :rewrite_request_params, only: %i[create]

    protected
      def devise_mapping
        @devise_mapping ||= Devise.mappings[account_name || :user]
      end

    private
      def rewrite_request_params
        return unless account_name
        request.params[account_name] = {
          email: params[:email],
          password: params[:password],
        }
      end

      def account_name
        @account_name ||= account.class.name.underscore.to_sym if account
      end

      def account
        return if params[:email].blank?
        return @account if defined? @account
        @account = CoreTeam.find_by(email: params[:email]) || User.find_by(email: params[:email])
      end
    end
  end
end

this will allow you to submit params to /api/v1/sign_in for both User and CoreTeam

First it will look for an account in core_teams table then users table. if found it will rewrite the request.params

# core_teams
$.post('/api/v1/sign_in', {
  "email": "[email protected]",
  "password": "Password21"
})

# users
$.post('/api/v1/sign_in', {
  "email": "[email protected]",
  "password": "Password20"
})