2017-10-06 16 views
0

나는 세 명의 다른 사용자 (관리자, 판매자, 뷰어)에게 권한을 부여하기 위해 pundit gem을 사용하고 있습니다. 현재 모든 것이 작동하고 관리자는 모든 것에 액세스 할 수 있으며 판매자는 자신의 제품을 볼 수 있으며 뷰어는 제품을 볼 수 있습니다.레일스 평단의 보석, 로그인하지 않은 사용자에게보기 허용

내가 가지고있는 유일한 결함은 signed_up/signed_in 사용자가 아닌 사용자가 검색 결과를 통해 제품을 볼 수 있도록하려는 것입니다. 현재 non 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 

는 업데이트와 동일합니다. 그것은 이미 의해 수행 될 때 컨트롤러에 많은 장소에서 두 번

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 

또한 사용자 권한을 부여됩니다 각 정책 클래스를 반복 할 필요가 없도록는 ApplicationPolicy에서 이렇게도 할 수 있습니다 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