ruby-on-rails - 使用 Pundit in Rails 限制整个 Controller 的 DRY 方法是什么?

标签 ruby-on-rails ruby authorization pundit

我正在使用 Pundit使用 Rails,我有一个 Controller ,我需要完全限制特定用户角色。我的角色是“员工”和“消费者”。工作人员应该可以完全访问 Controller ,但消费者应该没有访问权限。

有没有比逐个限制每个操作更 DRY 的方法?

例如,这是我的政策:

class MaterialPolicy < ApplicationPolicy
  attr_reader :user, :material

  def initialize(user, material)
    @user     = user
    @material = material
  end

  def index?
    user.staff?
  end

  def show?
    index?
  end

  def new?
    index?
  end

  def edit?
    index?
  end

  def create?
    index?
  end

  def update?
    create?
  end

  def destroy?
    update?
  end
end

还有我的 Controller :

class MaterialsController < ApplicationController
  before_action :set_material, only: [:show, :edit, :update, :destroy]

  # GET /materials
  def index
    @materials = Material.all
    authorize @materials
  end

  # GET /materials/1
  def show
    authorize @material
  end

  # GET /materials/new
  def new
    @material = Material.new
    authorize @material
  end

  # GET /materials/1/edit
  def edit
    authorize @material
  end

  # POST /materials
  def create
    @material = Material.new(material_params)
    authorize @material

    respond_to do |format|
      if @material.save
        format.html { redirect_to @material, notice: 'Material was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  # PATCH/PUT /materials/1
  def update
    authorize @material
    respond_to do |format|
      if @material.update(material_params)
        format.html { redirect_to @material, notice: 'Material was successfully updated.' }
      else
        format.html { render :edit }
      end
    end
  end

  # DELETE /materials/1
  def destroy
    authorize @material
    @material.destroy
    respond_to do |format|
      format.html { redirect_to materials_url, notice: 'Material was successfully destroyed.' }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_material
      @material = Material.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def material_params
      params.require(:material).permit(:name)
    end
end

有没有我不理解的方法可以做到这一点,或者 Pundit 的设计方式要求您明确说明?

最佳答案

第一步只是将调用移动到您的回调:

def set_material
  @material = Material.find(params[:id])
  authorize @material
end

如果您的 Pundit 版本是最新的(以前的版本返回 true/false 而不是记录),您还可以编写 @material = authorize Material.find(params[:id])

Pundit 在您选择如何使用它方面具有很大的灵 active 。例如,您可以创建一个 separate headless policy :

class StaffPolicy < ApplicationPolicy
  # the second argument is just a symbol (:staff) and is not actually used
  def initialize(user, symbol)
    @user = user
  end
  def access?
    user.staff?
  end
end

然后在回调中使用它来授权整个 Controller :

class MaterialsController < ApplicationController
  before_action :authorize_staff
  # ...

  def authorize_staff
    authorize :staff, :access?
  end
end

或者您可以只使用继承或混合来干燥您的策略类:

class StaffPolicy < ApplicationPolicy
  %i[ show? index? new? create? edit? update? delete? ].each do |name|
    define_method name do
      user.staff?
    end
  end
end

class MaterialPolicy < StaffPolicy
  # this is how you would add additional restraints in a subclass
  def show?
    super && some_other_condition
  end
end

Pundit 毕竟只是普通的老式 Ruby OOP。

关于ruby-on-rails - 使用 Pundit in Rails 限制整个 Controller 的 DRY 方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54545756/

相关文章:

ruby - Guard::RSpec 错误:未指定 cmd 选项,无法运行规范

java - 功能标记与授权

php - Laravel 5 API 授权用于使用 Facebook 进行授权的移动应用程序

ruby-on-rails - 为什么我在安装 Ruby bundler gem "ERROR: Failed to build gem native extension"时收到此错误消息?

ruby-on-rails - 找不到字段 "Netid"(Capybara::ElementNotFound)

ruby-on-rails - 尝试使用 bundle install 安装 ruby​​ oci8,我尝试单独安装它仍然无法正常工作

Ruby 嵌套赋值和无括号方法调用

android - 此堆栈跟踪是什么意思?按登录按钮时应用程序崩溃

ruby-on-rails - 每个 'when' block 中有多个值的 Case 语句

ruby-on-rails - 使用 rspec 测试 oauth2 get_token