Rails 5 - Pundit - 嵌套资源授权
Rails 5 - Pundit - authorisation for nested resource
我正在尝试弄清楚如何将 Pundit 与我的 Rails 5 应用程序一起使用。
我有提案、潜力和用户模型。这些协会是:
提案
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
我的期望是,由于我要求在 views/proposals/temporary_proposals.html.erb 部分(上方)中检查潜在政策并在下方提取,
<% if policy(pot).show? %>
注:pot定义为@proposal.potential.
我能看到的唯一逻辑错误是当前用户是用户而不是用户 ID。但是,如果我将“.id”附加到 current_user 的末尾,我会收到一个错误 "id is nil"。
Pundit 将查看该提案的潜在政策,并确定是否显示记录。
这是不对的,因为当我保存所有这些并尝试呈现提案显示时,我只能看到 :private_comment 属性不正确的可能性(但我确实满足第二个和第三个合格许可(即我创建了潜力和提案)- 所以我应该能够查看该记录)。
我的申请政策有:
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
但这给出了与上述尝试相同的错误结果。
谁能看出我错在哪里?
除非我遗漏了什么,@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 模型也值得指出 query methods exist for boolean attributes。这就是您能够 record.private_comment?
而不是 record.private_comment == true
.
的方式
我正在尝试弄清楚如何将 Pundit 与我的 Rails 5 应用程序一起使用。
我有提案、潜力和用户模型。这些协会是:
提案
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
我的期望是,由于我要求在 views/proposals/temporary_proposals.html.erb 部分(上方)中检查潜在政策并在下方提取,
<% if policy(pot).show? %>
注:pot定义为@proposal.potential.
我能看到的唯一逻辑错误是当前用户是用户而不是用户 ID。但是,如果我将“.id”附加到 current_user 的末尾,我会收到一个错误 "id is nil"。
Pundit 将查看该提案的潜在政策,并确定是否显示记录。
这是不对的,因为当我保存所有这些并尝试呈现提案显示时,我只能看到 :private_comment 属性不正确的可能性(但我确实满足第二个和第三个合格许可(即我创建了潜力和提案)- 所以我应该能够查看该记录)。
我的申请政策有:
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
但这给出了与上述尝试相同的错误结果。
谁能看出我错在哪里?
除非我遗漏了什么,@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 模型也值得指出 query methods exist for boolean attributes。这就是您能够 record.private_comment?
而不是 record.private_comment == true
.