Rails / Pundit - 将某些属性限制为某些用户角色

时间:2017-06-11 19:28:28

标签: ruby-on-rails pundit

所以我使用Pundit gem来允许/禁止用户访问路由,并且它可以正常工作。我有一定的要求,对于用户,管理员和非管理员都可以创建用户,但只有管理员可以限制用户(通过将restricted_at设置为DateTime.now来限制用户。)

所以管理员/非管理员都可以访问#create和#update操作,但它是我要授权的特定属性。

我的选择是:

  1. 我可以创建模型,但如果用户不是管理员,则只能使用restricted_at(如果已设置)
  2. 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角度来看,最有意义的是什么? - 如果非管理员尝试创建设置了restricted_at的用户,则返回401 Unauthorized,或更新现有用户的属性。我个人认为这是不好的,因为用户不是未经授权的路线,只是模型。毯子401并没有解释为什么。 - 创建模型,但只需要非管理员对该属性执行任何操作,就像我上面所做的那样 - 我可以在Pundit中添加模型错误(如果可能)或在控制器中添加模型错误(不太理想,我会在模型或专家中保留所有验证/权限。如果我将逻辑放在控制器中,然后我会在三个地方进行验证,模型,控制器和专家,这对我来说似乎很臭)

    为了说清楚,那些是可能的,但我想要的,我认为最好的是不创建模型(如果非管理员在创建时设置retricted_at),并返回错误消息。

    我该如何解决这个问题?感谢。

1 个答案:

答案 0 :(得分:0)

实现这一目标的一种方法是为管理员和用户使用不同的控制器和策略方法。例如:

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