Аутентификация нескольких моделей с помощью Authlogic

У меня несколько типов учетных записей пользователей, каждый с разной информацией. Например, деловые контакты ссылаются на компании, школьные администраторы и ученики - на школы. У студентов есть физические адреса, но деловые контакты и школьные администраторы используют адрес организации. Есть и другая информация, уникальная для каждого типа.

Я склоняюсь к отдельным таблицам для студентов, школьных администраторов и деловых контактов, но, используя Authlogic, у меня есть таблица Users с информацией для аутентификации (все должны войти в систему).

На самом деле вопрос в том, как лучше всего связать эту единую таблицу аутентификации с отдельными профилями. Похоже, что для однозначных отношений требуется одна таблица (например, Пользователи ‹-> Студенты или Пользователи ‹-> Business_contacts). Я хочу иметь что-то вроде отношений «один-к-одному из следующих» (Пользователи ‹-> Студенты или Business_contacts). Есть ли хороший способ сделать это с помощью таблицы соединений или другой конструкции?

В качестве альтернативы я мог бы объединить общую информацию в таблице «Пользователи» и создать столбец «профиль» в XML для поддержки уникальной информации. Я думал, что сохранение всего в чистых столбцах БД упростит выбор / вставку.

Мысли, идеи?


person JohnMetta    schedule 16.02.2010    source источник


Ответы (2)


Если вам действительно нужны отдельные модели для каждой используемой вами роли, я бы рекомендовал использовать полиморфную ассоциацию (подробнее здесь). Так:

# User model
belongs_to :owner, :polymorphic => true

# Student model
has_one :user, :as => :owner

# Any other model
has_one :user, :as => :owner

И вам нужно добавить в таблицу пользователей:

 t.integer :owner_id
 t.string  :owner_type
person klew    schedule 16.02.2010
comment
Именно то, что я искал. Я просто недостаточно внимательно изучил Active Record. Спасибо! - person JohnMetta; 17.02.2010
comment
Кстати, похоже, что в документации указано, что таблица пользователей может быть упрощена для использования t.references: owner,: polymorphic = ›true. Просто прочтите это, и вам будет легче читать. Ваше здоровье. - person JohnMetta; 17.02.2010
comment
references просто создает целочисленное поле и добавляет _id к имени поля. Так что то же самое. И читать действительно легче :) - person klew; 17.02.2010

деловые контакты связываются с предприятиями, школьные администраторы и студенты - со школами.

Это означает, что у вас разные роли пользователей, а не разные пользователи.

У учащихся есть физические адреса, но деловые контакты и школьные администраторы используют адрес организации. Есть и другая информация, уникальная для каждого типа.

Это означает, что разные роли имеют разные данные и поведение, что приводит к разным объектно-ориентированным классам.

На самом деле вопрос в том, как лучше всего связать эту единую таблицу аутентификации с отдельными профилями. Я хочу иметь что-то вроде отношений "один-к-одному из следующих" (Пользователи ‹-> Студенты или Business_contacts). Есть ли хороший способ сделать это с помощью таблицы соединений или другой конструкции?

Самая простая модель, которую я могу придумать, если следующее:

  • User (имя пользователя, адрес электронной почты, пароль, имена и другие общие данные для каждого пользователя)
  • Participant, аннотация. (имеет отношение к одному пользователю - определяет роль участника, поведение и его общие данные). Должен предоставить интерфейс для участников.
  • Student (наследуется от участника, добавляет свое поведение и данные)
  • SchoolAdministrator (наследуется от участника)
  • И так далее

В объектно-ориентированном мире (без СУБД) у этого есть простое преимущество: полиморфизм. Имея пользователя, вам не нужно точно знать, кто он. Вы просто делаете такие вещи:

user.participant.can_manage_stuff?
user.participant.order_book(harry_potter)

И будут выполнены соответствующие действия, которые будут реализованы в Student, SchoolAdministrator или другом классе, унаследованном от Participant.
Другое дело, что очень легко добавлять новые роли для системы. Просто унаследуйте от Participant и реализуйте его интерфейс.

Теперь, когда объектно-ориентированный дизайн завершен, давайте посмотрим на хранилище данных. Я предполагаю, что вы используете СУБД.

Итак, теперь у вас есть 2 типа ссылок:

  1. Однозначная связь между User и Participant.
  2. Обобщение (наследование) между Participant и Student, SchoolAdministrator.

Реализация 1-го так же проста, как наличие ассоциации has_one и / или belongs_to для следующей таблицы (через столбец participant_id):

пользователи: id | имя пользователя | электронная почта | пароль | и т. д. | Participant_id (ненулевое) Таблица FK_TO_participants |

Так что вы можете легко это реализовать.

Теперь вторая ссылка может быть реализована в СУБД в количестве разных вариантов .

Но, к счастью или к сожалению, ActiveRecord поддерживает только один вариант для этого. И это стратегия сопоставления иерархия на таблицу, которая использует столбец дискриминатор для различения типа (по соглашению хранится в столбце type).

Итак, у вас будет вторая таблица, которая выглядит так:

участники: id | тип | студент_карточка_номер (ноль) | номер_администратора (ноль) | и т.д

В этой таблице будут все столбцы для всех возможных участников. Это самая простая и легкая реализация иерархии в БД. Но не самый оптимальный с некоторых точек зрения. Как я уже сказал, с ActiveRecords в любом случае доступен только один вариант.

Таким образом, в результате этого дизайна вы получите 2 таблицы базы данных (пользователи, участники) и как минимум 3 класса (пользователь, участник, студент).

И, конечно, вы можете многое изменить здесь, но это должно передать мою точку зрения.

И да, пожалуйста, не используйте XML в базе данных, не тратьте зря нервы и драгоценное личное время.

Ваше здоровье.

person Dmytrii Nagirniak    schedule 16.02.2010
comment
Это именно то, что я искал. Я думаю, что мое замешательство было вызвано тем, что я не оценил сильную ORM Rails. Я думал об этом с точки зрения ООП, но не мог перевести это на РСУБД. Похоже, что Rails отлично поддерживает полиморфные ассоциации, так что я могу просто наследовать. Спасибо за подробное описание, это очень помогает прояснить мои мысли. - person JohnMetta; 17.02.2010