2017-10-06 88 views
0

我使用pundit gem爲了授予三個不同用戶(Admin,seller,viewer)的權限。目前我得到了一切工作,管理員可以訪問所有內容,賣家可以查看他們自己的產品,查看器可以查看產品。Rails pundit gem,允許查看非登錄用戶

我遇到的唯一問題是我希望非signed_up/signed_in用戶能夠通過搜索結果查看產品。現在,非sign_up/signed_in用戶可以看到搜索結果,但無法訪問節目視圖。

這裏是設置我有:

class ItemPolicy < ApplicationPolicy 
    attr_reader :item 

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

    def update? 
    @user.is_a?(Admin) ? item.all : @user.items 
    end 

    def index? 
    @user.is_a?(Admin) ? item.all : @user.items 
    end 

    def show? 
    @user.is_a?(Admin) ? item.all : @user.items 
    end 

    def create? 
    @user.is_a?(Admin) ? item.all : @user.items 
    end 

    def new? 
    @user.is_a?(Admin) ? item.all : @user.items 
    end 

    def edit? 
    @user.is_a?(Admin) ? item.all : @user.items 
    end 

    def destroy? 
    @user.is_a?(Admin) ? item.all : @user.items 
    end 

    class Scope < Struct.new(:user, :scope) 
    def resolve 
     if user.is_a?(Admin) 
     scope.where(:parent_id => nil) 
     elsif user.is_a?(Seller) 
     scope.where(:id => user.items) 
     end 
    end 

    def show? 
     return true if user.is_a?(Admin) 
     return true if user.seller_id == seller.id && user.is_a?(Seller) 
    false 
    end 
    end 
end 

控制器:

class ItemsController < ApplicationController 
    before_action :set_item, only: [:show, :edit, :update, :destroy] 


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

    def search 
    if params[:term] 
     @items = Item.search(params[:term]).order("created_at DESC") 
    else 
     @items = [] 
    end 
    end 


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


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


    def edit 
    authorize @item 
    @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 
    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]) 
     authorize @item 
    end 


    def item_params 
     params.require(:item).permit(:title, :description, :image, :price, :category_id) 
    end 
end 

application_contoller.rb

class ApplicationController < ActionController::Base 
    include Pundit 
    protect_from_forgery prepend: true 

    rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized 

    def pundit_user 
    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 

更新1

class ApplicationPolicy 
    attr_reader :user, :record 

    def initialize(user, record) 
    raise Pundit::NotAuthorizedError, "must be logged in" unless user 
    @user = user 
    @record = record 
    end 

    def index? 
    true # anybody can view 
    end 

    def show? 
    true # anybody can view 
    end 

    def search? 
    index? 
    end 

    def new? 
    create? 
    end 

    def edit? 
    update? 
    end 

    def destroy? 
    update? 
    end 

    private 
    # don't repeat yourself 
    def admin? 
    user.is_a?(Admin) 
    end 

    def seller? 
    user.is_a?(Seller) 
    end 
end 


class ItemPolicy < ApplicationPolicy 
    attr_reader :item 

    class Scope < Struct.new(:user, :scope) 
    def resolve 
     if admin? 
     scope.where(parent_id: nil) 
     elsif seller? 
     # avoids a query for user.items 
     scope.where(seller: user) 
     end 
    end 
    end 

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

    def update? 
    admin? || is_owner? 
    end 

    def create? 
    # just guessing here 
    admin? || seller? 
    end 

    private 

    def is_owner? 
    # or whatever the association between the item and its owner is 
    item.seller == user 
    end 
end 

回答

1

您正在混淆權威範圍和授權方法。 new?,show?等方法應返回一個布爾值,指示是否允許用戶執行操作。

要允許未經授權的用戶執行操作,只需返回true。 範圍用於縮小用戶有權訪問的記錄範圍。他們只有一個resolve方法。

class ApplicationPolicy 
    # ... 

    private 
    # don't repeat yourself 
    def admin? 
    user.is_a?(Admin) 
    end 

    def seller? 
    user.is_a?(Seller) 
    end 
end 


class ItemPolicy < ApplicationPolicy 
    attr_reader :item 

    class Scope < Struct.new(:user, :scope) 
    def resolve 
     if admin? 
     scope.where(parent_id: nil) 
     elsif seller? 
     # avoids a query for user.items 
     scope.where(seller: user) 
     end 
    end 
    end 

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

    def update? 
    admin? || is_owner? 
    end 

    def index? 
    true # anybody can view 
    end 

    def show? 
    true # anybody can view 
    end 

    def search? 
    index? 
    end 

    def create? 
    # just guessing here 
    admin? || seller? 
    end 

    def new? 
    create? 
    end 

    def edit? 
    update? 
    end 

    def destroy? 
    update? 
    end 

    private 

    def is_owner? 
    # or whatever the association between the item and its owner is 
    item.seller == user 
    end 
end 

除了重複自己(條件),您可以快捷地執行許多操作,因爲例如編輯的權限與更新相同。你甚至可以做到這一點的ApplicationPolicy,這樣你就不必再重複它在每個策略類:在您的控制器很多地方,因爲它是爲已經執行

class ApplicationPolicy 
    # ... 

    def index? 
    true # anybody can view 
    end 

    def show? 
    true # anybody can view 
    end 

    def search? 
    index? 
    end 

    def new? 
    create? 
    end 

    def edit? 
    update? 
    end 

    def destroy? 
    update? 
    end 

    private 
    # don't repeat yourself 
    def admin? 
    user.is_a?(Admin) 
    end 

    def seller? 
    user.is_a?(Seller) 
    end 
end 

class ItemPolicy < ApplicationPolicy 
    attr_reader :item 

    class Scope < Struct.new(:user, :scope) 
    def resolve 
     if admin? 
     scope.where(parent_id: nil) 
     elsif seller? 
     # avoids a query for user.items 
     scope.where(seller: user) 
     end 
    end 
    end 

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

    def update? 
    admin? || is_owner? 
    end 

    def create? 
    # just guessing here 
    admin? || seller? 
    end 

    private 

    def is_owner? 
    # or whatever the association between the item and its owner is 
    item.seller == user 
    end 
end 

您還授權用戶的兩倍set_item回調:

class ItemsController < ApplicationController 
    before_action :set_item, only: [:show, :edit, :update, :destroy] 

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

    def search 
    if params[:term] 
     @items = Item.search(params[:term]).order("created_at DESC") 
    else 
     @items = Item.none # Don't use [] as @items.none? for example would blow up. 
    end 
    end 


    def show 
    @comments = Comment.where(item_id: @item).order("created_at DESC") 
    authorize @item 
    end 


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


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


    def create 
    @item = authorize(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 
    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])) 
    end 


    def item_params 
     params.require(:item).permit(:title, :description, :image, :price, :category_id) 
    end 
end 
+0

感謝您的信息和幫助再次@最大!我根據你的回答更新了我的代碼,但仍然無法讓'非授權用戶'查看展示頁面......當用戶登錄時,他現在可以查看和編輯所有項目。我已經添加了更新1到我的問題,所以你可以看到我迄今爲止做了什麼。 – Theopap

+0

管理員可以查看和編輯所有項目。如果那不是你想要的更改#update中的邏輯?方法。此外,爲了讓無理由的用戶訪問資源,您需要跳過Devise'authorize_user!' (或者不管它是什麼)回調。 – max

+0

是的,這正是我想要的,管理員有權訪問所有項目,賣家只有他的項目,查看者只有搜索結果索引和顯示....但目前與您的更改...已登錄的賣家可以編輯/查看/刪除所有項目。 – Theopap

相關問題