How do I handle authentication with Devise when using multiple models in Rails 3.2 App

authentication, devise, ruby-on-rails, ruby-on-rails-3, single-table-inheritance

Solution

You can solve this using the following solution

def authenticate!
    if modelA_user_signed_in?
      @current_user = current_modelA
      true
    else
      authenticate_modelB!
    end

  end

Problem

I'm working on a Rails 3.2 app where I use Devise for authentication. I decided to try single table inheritance for managing user roles, but I quickly ran into a problem. I currently have three User models, `User < ActiveRecord`, `Admin < User` and `Collaborator < User`. Admin and Collaborator share most User columns, but they have slightly different behaviors and privileges. My models currently looks like this: ``` class User < ActiveRecord::Base devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :token_authenticatable # Setup accessible (or protected) attributes for your model attr_accessible :email, :name, :password, :password_confirmation, :remember_me before_save :ensure_authentication_token [...] end class Admin < User has_one :account, dependent: :destroy attr_accessible :account_attributes accepts_nested_attributes_for :account end class Collaborator < User has_one :account end class Account < ActiveRecord::Base attr_accessible :name validates_presence_of :name has_many :projects, dependent: :destroy has_many :users end ``` The problem aries when I try to authenticate Admins and Collaborators in my ProjectController (and other controllers where I need authentication): ``` # Causes problem, no one can access anything. before_filter :authenticate_admin! before_filter :authenticate_collaborator! ``` A similar problem I had was with devise's helper methods for ie. current_user, now I have current_admin and current_collaborator, I "solved" that by creating a before filter and method: ``` def set_current_user @current_user = current_admin || current_collaborator end ``` Is there a similar or simple solution for my authentication problem with Devise, or would you recommend another approach than Single Table Inheritance, and what would that be? My goal is, 1. when new users signs up, they become Admins, when they create their account, an Account model is also created. 2. The new (Admin) user can then invite additional users to the Account, which will be Collaborators. 3. Admins and Collaborators should have different privileges. Collaborators won't create new "Accounts" when they sign up (company could be a better name for my Account model) so Admin and Collaborators will need slightly different forms for signing up and editing. Thanks. Update I kinda "solved" it by creating a similar before filter: ``` def authenticate! if @current_user == current_admin :authenticate_admin! elsif @current_user == current_collaborator :authenticate_collaborator! end end ``` Suggestions on possibly more elegant solutions would still be appreciated.

Original source