2017-10-06 11 views
0

私はpundit gemを使用して3人の異なるユーザー(管理者、販売者、閲覧者)に権限を与えています。現在、私はすべての作業に取り組んでおり、管理者はすべてのものにアクセスし、自分の製品に売り手を持ち、視聴者は製品を見ることができます。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

あなたはPunditのスコープと認証方法を混同しています。 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

情報をお寄せいただきありがとうございますと@max再び助けます!私はあなたの答えに従って自分のコードを更新しましたが、まだ表示ページを表示するために '未許可のユーザー 'を取得することはできません...ユーザーがサインインしたときに、彼は今すぐすべてのアイテムを表示して編集できます。アップデート1を自分の質問に追加しました。これまでに何をしているのか分かりました。 – Theopap

+0

管理者はすべてのアイテムを表示および編集できます。あなたが#updateのロジックを変更したいと思わないなら、それは?方法。また、未登録のユーザーがリソースにアクセスできるようにするには、Devise 'authorize_user!'をスキップする必要があります。 (またはそれが何であれ)コールバック。 – max

+0

はいそれはちょうど私が、管理者がすべてにアクセスできるようにしたい、売り手だけのアイテム、ビューアのみ検索結果のインデックスと表示....しかし、現在あなたの変更...ログインした売り手ができる編集/表示/すべての項目を削除します。 – Theopap

関連する問題