Как обрабатывать аутентификацию с помощью Devise при использовании нескольких моделей в приложении Rails 3.2

Я работаю над Rails 3.2, где я использую Devise для аутентификации. Я решил попробовать одностраничное наследование для управления ролями пользователей, но я быстро столкнулся с проблемой. В настоящее время у меня три модели пользователей, User < ActiveRecord, Admin < User и Collaborator < User. Admin и Collaborator разделяют большинство столбцов пользователей, но они имеют несколько разные формы поведения и привилегии. Мои модели в настоящее время выглядят следующим образом:

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

Проблема возникает при попытке аутентификации админов и соавторов в моем ProjectController (и других контроллерах, где мне нужна аутентификация):

# Causes problem, no one can access anything.
before_filter :authenticate_admin!
before_filter :authenticate_collaborator!

Аналогичная проблема, с которой я столкнулся, заключалась в разработке вспомогательных методов для ie. current_user, теперь у меня есть current_admin и current_collaborator, я "решил", создав перед фильтром и методом:

def set_current_user
  @current_user = current_admin || current_collaborator
end

Есть ли аналогичное или простое решение для моей проблемы с аутентификацией с помощью Devise, или вы бы порекомендовали другой подход, чем однократное наследование, и что бы это было?

Моя цель: 1. Когда новые пользователи подписываются, они становятся админами, когда они создают свою учетную запись, также создается модель учетной записи. 2. Новый (администратор) пользователь может затем пригласить дополнительных пользователей на учетную запись, которая будет Collaborators. 3. Админы и соавторы должны иметь разные привилегии. Соавторы не будут создавать новые "Учетные записи" при регистрации (компания может быть лучшим именем для моей модели учетной записи), поэтому администратору и сотрудникам потребуется немного разные формы для регистрации и редактирования.

Спасибо.

Обновление

Я как бы "решил" его, создав аналогичный перед фильтром:

def authenticate!
  if @current_user == current_admin
    :authenticate_admin!
  elsif @current_user == current_collaborator
    :authenticate_collaborator!
  end
end

Предложения по возможно более элегантным решениям по-прежнему будут оценены.

Ответ 1

Вы можете решить это, используя следующее решение

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

  end

Ответ 2

Не уверен, что это все еще необходимо для решения этого...

Более элегантный способ иметь двойную аутентификацию может заключаться в следующем:

private

def authenticate!
   :authenticate_admin! || :authenticate_collaborator!
   @current_user = admin_signed_in? ? current_admin : current_collaborator
end

Затем вызовите before_filter: authenticate!

Если вам не нужна универсальная переменная @current_user, просто оставьте вторую строку.

Надеюсь, что это поможет.

Ответ 3

Вы можете разделить всю общую логику на модуль и использовать только одну таблицу.

module UserMethods
  #...
end

class User < ActiveRecord::Base
  include UserMethods
  devise ...

end  

class Admin < ActiveRecord::Base
  include UserMethods
  self.table_name = "users"
  devise ...
end

И сконфигурируйте все модели разработки отдельно в маршрутах, представлениях (при необходимости см. Конфигурирование видов). В этом случае вы можете легко обрабатывать всю логику.