У меня есть это приложение: Диспетчер задач.
У меня есть User
.
Groups
->, после чего он становится администратором созданных им групп.Member
(средней таблицей между пользователем и группой) группы, созданной другим пользователем.Итак, у меня есть этот пользователь:
has_many :groups, foreign_key: :admin_id, dependent: :destroy
has_many :groups, through: :members
А теперь я хочу спросить у Дб:
Скорее всего, я смогу создать SQL-запрос для этого, но я думал, что будет больше способов работы с Rails.
Есть ли способ сделать это? Я могу думать только о том, чтобы иметь пользователя, но в то же время разделить его на 2 разных подкласса, таких как UserAdmin и NormalUser. Но я не уверен, как это сделать и правильный ли это подход.
Заранее спасибо!
Разделение вашего класса User на несколько классов не является решением, поскольку вы хотите, чтобы пользователи могли иметь разные роли в разных группах. Скорее есть несколько различных решений.
Если вы хотите иметь определенную связь между пользователем и группой, вы можете добавить отдельную ассоциацию:
class AddCreatorToGroups < ActiveRecord::Migration[7.0]
def change
# note that you'll have to worry about filling this
# column if you have existing data
add_reference :groups, :founder, null: false, foreign_key: { to_table: :users }
end
end
class Group
# ...
belongs_to :founder,
class_name: 'User',
inverse_of: :groups_as_founder
end
class User
# ...
has_many :groups_as_founder,
class_name: 'Group',
foreign_key: :founder_id,
inverse_of: :founder
end
Это хорошая идея, если вам нужно очень эффективно загружать группу и только этого пользователя. Это будет установлено при создании группы:
def create
@group = Group.new(group_params) do |group|
group.founder = current_user
end
# ...
end
Это можно комбинировать с другими вариантами. Это не решит ситуацию, когда вы хотите назначить несколько администраторов в группу.
class AddCreatorToGroups < ActiveRecord::Migration[7.0]
def change
add_columns :memberships, :role, :integer, default: 0
end
end
class Membership < ApplicationRecord
belongs_to :group
belongs_to :member, class_name: 'User'
enum :role, {
normal: 0,
admin: 1
}
end
class Group < ApplicationRecord
has_many :normal_memberships,
class_name: 'Membership',
-> { Membership.normal }
has_many :admin_memberships,
class_name: 'Membership',
-> { Membership.admin }
has_many :normal_members,
class_name: 'User',
through: :normal_memberships
has_many :admin_members,
class_name: 'User',
through: :admin_memberships
end
class User < ApplicationRecord
has_many :normal_memberships,
class_name: 'Membership',
-> { Membership.normal }
has_many :admin_memberships,
class_name: 'Membership',
-> { Membership.admin }
has_many :groups_as_normal_member,
class_name: 'Group',
through: :normal_memberships
has_many :groups_as_admin_member,
class_name: 'Group',
through: :admin_memberships
end
Это очень упрощенный пример, в котором доступные роли определяются через перечисление в таблице членства. В более сложном примере роль может быть определена как role_id
, указывающая на отдельную таблицу.
Этого повторения можно избежать, зациклившись на Membership.roles.key
.
Одна вещь, которую следует учитывать, это то, что это возлагает много обязанностей на класс Membership.
Дополнительной альтернативой может быть использование отдельной системы, такой как Rolify, и совершенно другого набора таблиц для хранения ролей в группе. Существует множество руководств о том, как использовать Rolify или создать систему доступа на основе ролей с нуля, если вы немного поискали.
Обратите внимание, что я использовал membership
, а не member
намеренно.
Спасибо!! Когда вы говорите, что членство принадлежит члену, мне трудно это понять. Моя текущая структура: User -> Member <- Group, поскольку отношение между пользователем и группой: многие ко многим. Почему тогда членство принадлежит участнику и группе, а не пользователю и группе? Спасибо за удивительный ответ кстати!
Это не дополнительный стол. То, что вы называете Member, должно называться Membership. В английском языке вы можете быть членом группы, но это наречие — существительное означает членство, если вы не говорите о человеке. Например, у вас будет членская карта, и это действительно то, что представляет эта таблица.
Это дает название, которое действительно имеет смысл для носителей английского языка — пользователь has_many :memberships
. И группа has_many :members, through: :memberships, class_name: 'User'
.
А как насчет промежуточной модели (у вас, кажется, уже есть таблица
member
) сuser_id
,group_id
иrole
. Последнее может быть'member'
или'admin'
, чтобы указать роль пользователя в этой группе. Таким образом, у вас есть одна таблица для запроса, и вы можете легко иметь несколько администраторов в группе (по крайней мере, технически).