Rails/Pundit - ограничить определенные атрибуты определенными ролями пользователей

Поэтому я использую гем Pundit, чтобы разрешить / запретить пользователям доступ к маршрутам, и для этого он работает нормально. У меня есть определенное требование, когда для пользователей, как администратор, так и не администратор, могут создать пользователя, но только администратор может ограничить пользователя (пользователи ограничены, установив для параметра limit_at значение DateTime.now).

Таким образом, к действиям #create и #update могут обращаться как администраторы, так и не администраторы, но это особый атрибут, который я хочу авторизовать.

Мои варианты:

  1. Я мог бы просто создать модель, но с ограниченным значением (если установлено), если пользователь не является администратором.

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
Другие вопросы по тегам