Rails 5-Pundit-嵌套资源的授权



我正试图弄清楚如何在Rails5应用程序中使用Pundit。

我有"提案"、"潜在"one_answers"用户"的模型。关联为:

建议书

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

我对每一种资源都有专家政策。

我目前正在努力弄清楚如何实施规则,以便只有在应用规则的情况下才能显示潜力。

我的潜力显示在保存在我的提案视图文件夹中的部分中。它有:

<% @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? %> 

注:pot定义为@proposal.potential.

我在这篇文章中看到的唯一逻辑错误是,当前用户是用户,而不是用户id。但是,如果我在current_user的末尾附加".id",我会得到一个错误,说"id为nil"。

专家将研究该提案的潜在政策,并决定是否显示该记录。

这是不对的,因为当我保存所有这些并尝试呈现提案时,我只能看到:private_comment属性不为true的潜在权限(但我确实符合第二个和第三个合格权限的标准(即我创建了潜在权限和提案),所以我应该能够查看该记录)。

我的应用程序策略有:

class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end

我理解这意味着,由于我的潜在策略继承自我的应用程序策略,我应该能够引用@record来表示该策略试图处理的记录。对我来说,这意味着我应该能够将表演动作定义为:

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

但这给出了与上述尝试相同的错误结果。

有人看到我哪里搞错了吗?

除非我遗漏了什么,否则@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的重复评估)和更干净的代码。

同样值得指出的是,rails模型上存在布尔属性的查询方法。这就是您能够执行record.private_comment?而不是record.private_comment == true的方法。

最新更新