Rails/Pundit - ограничить определенные атрибуты определенными ролями пользователей
Поэтому я использую гем Pundit, чтобы разрешить / запретить пользователям доступ к маршрутам, и для этого он работает нормально. У меня есть определенное требование, когда для пользователей, как администратор, так и не администратор, могут создать пользователя, но только администратор может ограничить пользователя (пользователи ограничены, установив для параметра limit_at значение DateTime.now).
Таким образом, к действиям #create и #update могут обращаться как администраторы, так и не администраторы, но это особый атрибут, который я хочу авторизовать.
Мои варианты:
- Я мог бы просто создать модель, но с ограниченным значением (если установлено), если пользователь не является администратором.
class UserPolicy
def create?
@record.assign_attributes({restricted_at: nil}) unless @user.admin?
return true
end
end
Но я не думаю, что это лучший способ сделать это. Я бы предпочел вернуть ошибку здесь. Однако, если я пытаюсь добавить ошибку вроде @record.errors.add(:restricted_at, "can only be set by admin")
затем в контроллере, когда вызывается save, он будет повторно проверен, и поскольку проверки моделей не проверяют, кто что-то изменяет.
Так есть ли способ сделать это с Pundit? Что имеет больше смысла с точки зрения пользователя /UX? - Вернуть 401 Несанкционированный, если не администратор пытается создать пользователя с установленным ограниченным_катом, или обновить атрибут существующего пользователя. Лично я считаю, что это плохо, потому что пользователи не несанкционированы для маршрута, только для модели. И одеяло 401 не объясняет ПОЧЕМУ. - Создайте модель, но просто удалите все, что не администратор делает с этим атрибутом, как я делаю выше - Некоторые альтернативы, где я либо добавляю ошибку модели с Pundit(если возможно), либо в контроллере (менее идеальный, я бы предпочел сохраните всю информацию о проверке / разрешении в модели или в pundit. Если я добавлю логику в контроллер, то у меня будут проверки в трех местах: модель, контроллер и pundit, что мне кажется вонючим)
Просто чтобы прояснить, это возможные варианты, но я хочу, и то, что я считаю лучшим, это НЕ создавать модель (если не администратор устанавливает retricted_at при создании) и возвращать сообщение об ошибке.
Как я могу разобраться в этом? Благодарю.
1 ответ
Один из способов добиться этого - использовать разные контроллеры и методы политики для администраторов и пользователей. Например:
class UsersController < ApplicationController
def create
@user = User.create(user_params)
# ...
end
def update
@user.update_attributes(user_params)
# ...
end
private
def user_params
params.require(:user).permit(
# permit only attributes that are accessible by non-admins
)
end
end
и там будет Admins::UsersController
с действиями, которые принимают все доступные параметры:
class Admins::UsersController < ApplicationController
before_action :authorize_user!
# ...
private
def authorize_user!
authorize @user, :admin_manage?
end
def user_params
params.require(:user).permit(
# permit all attributes that are accessible by admins
)
end
end
Тогда в UserPolicy
:
class UserPolicy
def admin_manage?
@user.admin?
end
end