首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rails:适用于三个用户的基本pundit gem设置

Rails:适用于三个用户的基本pundit gem设置
EN

Stack Overflow用户
提问于 2017-10-05 19:48:34
回答 2查看 272关注 0票数 0

我正在使用devise,并且我遵循this来设置三个用户(管理员、卖家、查看者)。每个用户都将其放在modelsession_controllerregistration_conttrolerviews文件夹中,其中包含与每个用户关联的所有视图。

现在,我正在尝试实现pundit gem,以便在每个controller中设置权限。

在尝试登录localhost:3000/items时,我收到以下错误:unable to find policy of nil Pundit::NotDefinedError in ItemsController#index

这就是我在items_controller中尝试做的事情

代码语言:javascript
复制
class ItemsController < ApplicationController
  before_action :set_item, only: [:show, :edit, :update, :destroy]


  def index
    authorize @item
    @items = Item.all
  end

  def show
    authorize @item
    @comments = Comment.where(item_id: @item).order("created_at DESC")
    @items = Item.find(params[:id])
    end

  def new
    authorize @item
    @item = Item.new
    @categories = Category.order(:name)
  end


  def edit
    authorize @item
    @categories = Category.order(:name)
  end

  def create
    authorize @item
    @item = Item.new(item_params)

    respond_to do |format|
      if @item.save
        format.html { redirect_to @item, notice: 'Item was successfully created.' }
        format.json { render :show, status: :created, location: @item }
      else
        format.html { render :new }
        format.json { render json: @item.errors, status: :unprocessable_entity }
      end
    end
  end


  def update
    authorize @item
    respond_to do |format|
      if @item.update(item_params)
        format.html { redirect_to @item, notice: 'Item was successfully updated.' }
        format.json { render :show, status: :ok, location: @item }
      else
        format.html { render :edit }
        format.json { render json: @item.errors, status: :unprocessable_entity }
      end
    end
  end


  def destroy
    authorize @item
    @item.destroy
    respond_to do |format|
      format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    def set_item
      @item = Item.find(params[:id])
    end
end

application_controller.rb

代码语言:javascript
复制
class ApplicationController < ActionController::Base
  include Pundit
  protect_from_forgery prepend: true

  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  def pundit_user
    CurrentContext.new(current_seller, current_admin, current_viewer)
  end

  private

  def user_not_authorized(exception)
    policy_name = exception.policy.class.to_s.underscore
    flash[:warning] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default
    redirect_to(request.referrer || root_path)
  end
end

models/current_context.rb

代码语言:javascript
复制
class CurrentContext
  attr_reader :seller, :admin, :viewer

  def initialize(seller, admin, viewer)
    @seller = seller
    @admin = admin
    @viewer = viewer
  end
end

策略/application_policy.rb

代码语言:javascript
复制
class ApplicationPolicy
  attr_reader :seller, :record, :admin, :viewer

  def initialize(context, record)
     raise Pundit::NotAuthorizedError, "must be logged in" unless context
    @seller = context.seller
    @admin = context.admin
    @viewer = context.viewer
    @record = record
  end

  def index?
    false
  end

  def show?
    scope.where(:id => record.id).exists?
  end

  def create?
   false
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  def scope
    Pundit.policy_scope!(user, record.class)
  end

  class Scope
    attr_reader :seller, :admin, :viewer, :scope

    def initialize(context, scope)
      @seller = context.seller
      @admin = context.admin
      @viewer = context.viewer
      @scope = scope
    end

    def resolve
      scope
    end
  end
end

policies/item_policy.rb

我想说的是..。管理员要有完全的访问权限,而卖家只能创建、编辑、更新、删除自己的内容。

代码语言:javascript
复制
class ItemPolicy < ApplicationPolicy
  attr_reader :item

  def initialize(user, item)
    super(user, item)
    @user = user
    @item = record
  end

  def update?
    @user.is_a?(Admin) || @item.try(:user) == @user
  end

  def index?
    @user.is_a?(Admin) || @item.try(:user) == @user
  end

  def show?
    @user.is_a?(Admin) || @item.try(:user) == @user
  end

  def create?
    @user.is_a?(Admin) || @item.try(:user) == @user
  end

  def new?
    @user.is_a?(Admin) || @item.try(:user) == @user
  end

  def edit?
    @user.is_a?(Admin) || @item.try(:user) == @user
  end

  def destroy?
   @user.is_a?(Admin) || @item.try(:user) == @user
  end
end
EN

回答 2

Stack Overflow用户

发布于 2017-10-05 22:41:43

检查控制器的索引操作,您的@item为空。更改索引操作,如下所示:

代码语言:javascript
复制
  def index
    authorize Item
    @items = Item.all
  end
票数 1
EN

Stack Overflow用户

发布于 2017-10-05 23:09:31

在Pundit中,您可以传递类来授权与特定实例不对应的操作:

代码语言:javascript
复制
def index
  authorize Item
  @items = policy_scope(Item)
end

另外,养成使用policy_scope的习惯--它可以让你控制策略中哪些记录是可用的。

#new和create中声明实例变量之前,还需要使用@item实例变量:

代码语言:javascript
复制
def new
   @item = Item.new(item_params)
   authorize @item
end

你也可以通过在你的set_item回调中授权来大大地干燥控制器:

代码语言:javascript
复制
class ItemsController < ApplicationController
  before_action :set_item, only: [:show, :edit, :update, :destroy]


  def index
    authorize Item
    @items = policy_scope(Item)
  end

  def show
    # Use the association
    @comments = @item.comments.order("created_at DESC")
  end

  def new    
    @item = Item.new
    authorize @item
    @categories = Category.order(:name)
  end


  def edit
    @categories = Category.order(:name)
  end

  def create
    @item = Item.new(item_params)
    authorize @item
    respond_to do |format|
      if @item.save
        format.html { redirect_to @item, notice: 'Item was successfully created.' }
        format.json { render :show, status: :created, location: @item }
      else
        format.html { render :new }
        format.json { render json: @item.errors, status: :unprocessable_entity }
      end
    end
  end


  def update
    respond_to do |format|
      if @item.update(item_params)
        format.html { redirect_to @item, notice: 'Item was successfully updated.' }
        format.json { render :show, status: :ok, location: @item }
      else
        format.html { render :edit }
        format.json { render json: @item.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @item.destroy
    respond_to do |format|
      format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    def set_item
      @item = authorize( Item.find(params[:id]) )
      # Or if you are using an older version of Pundit
      # @item = Item.find(params[:id])
      # authorize @item
    end
end
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46584860

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档