У меня есть приложение rails, у которого есть три разных типа пользователей, и мне нужно, чтобы они все использовали одну и ту же информацию общего профиля. Однако каждый отдельный пользователь также имеет уникальные атрибуты. Я не уверен, как выделить разные поля.
- Администратор (администратор всего сайта)
- Владелец (магазина / и т. Д.)
- Член (например, член кооператива)
Я использую devise для аутентификации и cancan для авторизации. Поэтому у меня есть модель User с набором ролей, которые могут быть применены к пользователю. Этот класс выглядит так:
class User < ActiveRecord::Base
# ... devise stuff omitted for brevity ...
# Roles association
has_many :assignments
has_many :roles, :through => :assignments
# For cancan: https://github.com/ryanb/cancan/wiki/Separate-Role-Model
def has_role?(role_sym)
roles.any? { |r| r.name.underscore.to_sym == role_sym }
end
end
У каждого пользователя есть профиль, который включает:
- Имя и Фамилия
- Информация об адресе (город / улица / почтовый индекс / и т. Д.)
- Телефон
Я не хочу загрязнять модель пользователя этой информацией, поэтому я добавляю ее в модель профиля. Эта часть довольно проста. Это превращает модель User в нечто подобное:
class User < ActiveRecord::Base
# ... devise stuff omitted for brevity ...
# ... cancan stuff omitted for brevity ...
has_one :profile
end
В дополнительных полях я испытываю беспокойство по поводу того, как моделировать ...
Если пользователь является администратором, у него будут уникальные поля, такие как:
- admin_field_a: строка
- admin_field_b: строка
- и т.д.
Если пользователь является владельцем, у него будут уникальные поля ...
- stripe_api_key: строка
- stripe_test_api_key: строка
- stripe_account_number: строка
- has_one: store # AR Ссылка на другую модель, которой нет у Admin и Member.
Если пользователь является участником, у него будет несколько дополнительных полей:
- stripe_account_number: строка
- own_to: store # магазин, членом которого они являются
- has_many: note
...
и модель магазина будет содержать has_many для участников, поэтому мы работаем с членами магазина.
Проблема связана с дополнительными полями. Я устанавливаю это как различные классы? Поместите их в другой
В настоящее время я пробовал несколько разных способов установить это:
Один из способов - настроить модель пользователя в качестве совокупного корня
class User < ActiveRecord::Base
# ...
# Roles association
has_many :assignments
has_many :roles, :through => :assignments
# Profile and other object types
has_one :profile
has_one :admin
has_one :owner
has_one :member
# ...
end
Преимущество этого подхода в том, что модель User является корневой и может получить доступ ко всему. Недостатком является то, что если пользователь является «владельцем», то ссылки «admin» и «member» будут равны нулю (и декартовой системе других возможностей - admin, но не владельца или участника и т. Д.).
Другой вариант, о котором я думал, состоял в том, чтобы каждый тип пользователя наследовал от модели User как таковой:
class User < ActiveRecord::Base
# ... other code removed for brevity
has_one :profile
end
class Admin < User
# admin fields
end
class Owner < User
# owner fields
end
class Member < User
# member fields
end
Проблема в том, что я загрязняю объект User всеми видами nil в таблице, где одному типу не нужны значения из другого типа / etc. Просто выглядит немного грязно, но я не уверен.
Другой вариант состоял в том, чтобы создать каждый тип учетной записи в качестве корневого, но иметь пользователя в качестве дочернего объекта, как показано ниже.
class Admin
has_one :user
# admin fields go here.
end
class Owner
has_one :user
# owner fields go here.
end
class Member
has_one :user
# member fields go here.
end
Проблема с вышесказанным заключается в том, что я не уверен, как загрузить соответствующий класс после входа пользователя. У меня будет их user_id, и я смогу определить, какая у него роль (из-за роли ассоциация на пользовательской модели), но я не уверен, как перейти от пользователя UP к корневому объекту. Методы? Другой?
Заключение
У меня есть несколько разных способов сделать это, но я не уверен, что правильный подход "рельсы". Как правильно моделировать это в рельсах AR? (Бэкэнд MySQL). Если не существует «правильного» подхода, что является лучшим из вышеперечисленного (я также открыт для других идей).
Спасибо!