У меня был большой успех с помощью state_machine и я люблю методы класса, которые он динамически создает через несколько строк кода.
Однако я не уверен, как продолжить работу с создаваемой системой. В настоящее время я разрабатываю систему, в которой пользователи имеют много ролей. Таким образом, это не так просто, как наличие пользователя, состояние которого от неподтвержденного до подтверждено, а затем потенциально возможно admin.
Теперь пользователь имеет много ролей и может быть потенциальным, велосипедистом, координатором, manger strong > , форум admin, администратор магазина, супер админ и сборщик средств.
Итак, иерархия выглядит следующим образом:
суперамин
форум admin, магазин admin
велосипедист, координатор, manger, сборщик средств
потенциал
Однако один конечный автомат здесь не будет вырезать, поскольку вполне возможно, что один пользователь может одновременно использовать все вышеперечисленные роли.
Я реализую свои собственные методы класса, подобные этому, чтобы немного сортировать состояние машины:
class User < ActiveModel::Base
has_many :jobs
has_many :roles, through: :jobs
def role_array
self.roles.pluck(:role)
end
def has_role?(role)
role_array.include?(role)
end
# checking
def is_superadmin?
role_array.include?('superadmin')
end
# changing
def add_role(role)
self.update_attributes(accepted_at: Time.now) if self.is_only_potential?
self.user_roles.create(role_id: Role.find_by(role: role).id ) if !self.has_role?(role)
end
def remove_role(role)
self.user_roles.find_by( role_id: Role.find_by(role: role).id ).destroy if self.has_role?(role)
end
def make_superadmin!
add_role('superadmin')
end
def denounce_superadmin!
remove_role('superadmin')
end
end
И это всего лишь битва. Поэтому мои вопросы:
1) Я делаю это правильно? Как вы будете обрабатывать пользователей с несколькими ролями?
2) Даже если я делаю это правильно, я бы хотел создать DSL state_machine-esque, поэтому, когда мне нужно создать новую роль, скажем, "бегун", я могу просто сделайте что-то подобное в моей модели:
class User < ActiveModel::Base
has_many :jobs
has_many :roles, through: :jobs
multiroles initial: :potential do
roles [:superadmin, :forum_admin, :store_admin, :cyclist, :coordinator, :manager, :fundraiser, :potential]
# dynamically creates the above methods for getting and setting for all roles
end
Как мне создать этот метод мультиролей? Внутри lib
? готовый быть упакован как мой первый драгоценный камень?
Я не знаю, как динамически создавать методы, но я бы хотел начать:)
Просто мысль, возможно, метод multiroles
мог бы динамически получить все роли через Roles.all
и автоматически добавить вышеуказанные методы! Возможно, даже позаботьтесь о has_many :jobs
has_many :roles, through: :jobs
Также, как я должен аутентифицировать эти роли? В настоящее время я делаю это в блоке перед моими контроллерами:
def only_superadmins
redirect_to root_url if !current_user.has_role?('superadmin')
end
У меня также есть куча этих методов в моем контроллере приложений, only_superadmins
, only_cyclists
ect и я вызываю их с помощью метода before_method
в разных субконтроллерах.
Это нормально? Должен ли я использовать канкан или что-то еще?
Если я делаю это правильно, мне интересно, как я должен динамически создавать эти методы с помощью Gem. Я думаю что-то в этом роде:
class panel_controller < ApplicationController
allowed_roles [:super_admin, :forum_admin, :store_admin]
end
и метод allowed_roles создаст эти методы
def allowed_roles(role_array)
role_array.each do |role|
define "only_#{role.to_s}s" do |arg|
redirect_to root_url if !current_user.has_role?(arg.to_s)
end
end
end
Итак, чтобы программно создать эти методы:
def only_super_admins
redirect_to root_url if !current_user.has_role?('super_admin')
end
def only_forum_admins
redirect_to root_url if !current_user.has_role?('forum_admin')
end
def only_store_admins
redirect_to root_url if !current_user.has_role?('store_admin')
end
Пока я не понимаю, почему это не сработает, это не кажется мне слишком эффективным.
Может быть, allowed_roles
должен выглядеть так:
def allowed_roles(wanted_roles)
redirect_to root_url unless (current_user.role_array & wanted_roles).empty? # it ONLY empty when any of the current_user roles exists in the wanted_roles array
end
Мне просто нужны некоторые указатели:)
Как создать драгоценный камень, чтобы сделать доступным для модели allowed_roles
метод и multiroles
для модели пользователя?
Может ли cancan
управлять несколькими ролями, как это? Должен ли я просто использовать это?