2017-01-17 23 views
0

Rails 5アプリケーションでPunditを使用する方法を理解しようとしています。Rails 5 - Pundit - ネストされたリソースの承認

私は提案、潜在的およびユーザーのためのモデルを持っています。団体は以下のとおりです。

has_many :potentials, inverse_of: :proposal 
    accepts_nested_attributes_for :potentials, reject_if: :all_blank, allow_destroy: true 

belongs_to :user 

潜在

提案

belongs_to :proposal, inverse_of: :potentials 
    belongs_to :user 

ユーザー

has_many :proposals, dependent: :destroy 
    has_many :potentials 

私は、これらのリソースのそれぞれについて、評論家のポリシーを持っています。

現在、ルールの実装方法を理解するために苦労しており、ルールが適用される場合にのみポテンシャルが表示されます。

私のポテンシャルは、私のプロポーザルビューフォルダに部分的に保存されています。それはあります

私の提案コントローラ、showアクションで
<% @proposal.potentials.each do | pot | %> 
     <div class="panel"> 
      <% if policy(pot).show? %> 
       <% if pot.private_comment == true %> 
        <p> <%= render :text => 'CONFIDENTIAL - NOT FOR PUBLIC DISCLOSURE' %></p> 
        <% end %> 
         <p><%= pot.comment %> 
         </p> 
         <p style = "color: navy; text-align:right"><%= pot.user.full_name %>, <%= pot.user.organisation.title.titleize %></p> 

         <p style="font-style:italic; color: #FFFFFF; float:right"><%= text_for_status(pot)%></p> 
        </div> 
       <% end %> 
     <% end %> 

、私が持っている:私の潜在的な政策で

before_action :set_proposal, only: [:show, :edit, :update, :destroy ] 

def show 
     @potentials = @proposal.potentials 
end 

private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_proposal 
     @proposal = Proposal.find(params[:id]) 
     authorize @proposal 
    end 

を、私は本当のこと記載された3つの条件のいずれかのようにショーのためのルールを定義します。

class PotentialPolicy < ApplicationPolicy 


    def index? 
    true 
    end 

    def show? 
true if record.private_comment != true || 
     if record.private_comment == true && @current_user == record.user_id || 
     if record.private_comment == true && @current_user == record.proposal.user_id 
     else false 
     end 
     end 

エンド

def new? 
    true 
    end 

    def create? 
    true 
    end 

    def edit? 
    update? 
    end 

    def update? 
    true if record.user_id == current_user.id 
    end 

    def destroy? 
    false 
    end 

end 

私の期待は、私は潜在的な政策を求めるため、ビュー/提案にチェックすることです/ temporary_proposals.html.erb部分(上)と、以下の抽出、

<% if policy(pot).show? %> 

注:ポットは@proposalとして定義されます。潜在的な。

私が見ることができる唯一の論理エラーは、現在のユーザーはユーザーIDではなくユーザーです。しかし、 ".id"をcurrent_userの末尾に追加すると、 "id is nil"というエラーが表示されます。

Punditは、そのプロポーザルの潜在的なポリシーを見て、そのレコードを表示するかどうかを判断します。

これをすべて保存してプロポーザルを表示しようとすると、private_comment属性が真でない可能性がわかります(ただし、2番目と3番目の適格許可の基準を満たしています私はその可能性と提案を作りました) - その記録を見ることができるはずです)。

私のアプリケーションポリシーがあります。

class ApplicationPolicy 
    attr_reader :user, :record 

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

が、私はこれが私の潜在的なポリシーは、私のアプリケーションポリシーを継承しているので、私はこの方針をしようとしているレコードを意味する@recordを参照することができなければならないことを意味するために理解しますハンドル。私にとって、それは私のようにshowアクションを定義することができるはずです意味:

def show? 
    true if record.private_comment != true || 
      if record.private_comment == true && @current_user == @record.user || 
      if record.private_comment == true && @current_user == @record.proposal.user 
      else false 
      end 
    end 
    end 

しかし、これは、上記の試みと同じ間違った結果を与えます。

誰かが私が間違っているのを見ることができますか?

答えて

1

私が何かを逃していない限り、お客様のポリシーに@current_userが定義されていません。どのようにあなたのshow?方法簡素化について:

def show? 
    return true unless record.private_comment? 

    return [ record.user_id, record.proposal.user_id ].include? user.id 
end 

を私はあなたがやったように、巨大な条件文を構築すると思う行動のための警備員を通じて考えたときに、共通のトラップです。

ガードの失敗や成功への可能な限り最短の経路を別々に考えてみると、ポリシーの方がはるかに読みやすく、書きやすくなります。これらを奇妙なエッジケースで、必要に応じてデフォルト(通常false)にします。

(繰り返しの評価がrecord.private_comment == trueのように)とクリーナーコードが少なくなります。

レールモデルでquery methods exist for boolean attributesを指摘する価値もあります。これは、record.private_comment == trueの代わりにrecord.private_comment?を実行する方法です。

+1

ありがとうございました。それは本当に明白です。 – Mel

関連する問題