如何仅更新 rails 6 中 current_user 的嵌套表单属性?
Posted
技术标签:
【中文标题】如何仅更新 rails 6 中 current_user 的嵌套表单属性?【英文标题】:How to update the nested form attributes of only the current_user in rails 6? 【发布时间】:2021-10-22 12:18:25 【问题描述】:我的 rails 6 应用程序中有一个“用户”、“任务”和“评论”模型。用户模型是使用用于身份验证的设计来定义的。用户 has_many cmets 和 has_many 任务和任务 has_many cmets。 我有一个“任务”的嵌套表单,它接受_嵌套属性_用于“评论”。像这样的:
<%= form_with model: @task do |f| %>
<%= f.text_field(:name) %>
<br><br>
<%= form.fields_for :comments do |c| %>
<%= render('comment_fields', f: c) %>
<% end %>
<%= link_to_add_association('Add comment', f, :comments) %>
<%= f.submit %>
<% end %>
“_comment_fields.html.erb”文件如下所示:
<div class="nested-fields">
<%= f.text_area(:body) %>
<%= link_to_remove_association('Remove comment', f) %>
</div>
以上两种形式只是原始代码的最小版本,我在这里使用它们仅供参考。 现在,假设名为“user1”的用户使用数据库中的任务表单添加了一个名为“task1”的任务,并且还使用 cmets 的嵌套表单添加了一些 cmets。 我想要的是,如果其他名为“user2”的用户尝试编辑任务“task1”,那么他/她应该能够使用此表单仅添加和编辑他的 cmets,并且只能编辑任务名称,而“user2”不应该能够编辑或删除其他人的 cmets,但只能是他的。我们将如何为嵌套表单执行此操作。
我们可以用一些正常的形式来实现这个功能,比如:
<% if @task.user.id == current_user.id %>
<%= f.text_field(:name) %>
<% end %>
只有当当前模型的 user_id 与当前登录用户的 id 匹配时,上面的代码才会显示 text_field,但我不知道如何在 f.fields_for 中执行此操作,因为我们在 a 中没有像 @task 这样的变量嵌套形式。
【问题讨论】:
我删除了 apache-cocoon 标签。它与茧宝石完全无关。 【参考方案1】:你可以通过object
属性获取form builder instance包裹的对象:
<div class="nested-fields">
<%= f.text_area(:body) %>
<% if f.object.user == current_user %>
<%= link_to_remove_association('Remove comment', f) %>
<% end %>
</div>
但是,我并不鼓励您重新发明authorization ***。 Pundit 或 CanCanCan gem 是最流行的选择,可以避免在您的视图和控制器中传播和复制身份验证逻辑。
使用 Pundit,您可以:
class CommentPolicy < ApplicationPolicy
def destroy?
record.user == user
end
end
<div class="nested-fields">
<%= f.text_area(:body) %>
<% if policy(f.object).destroy? %>
<%= link_to_remove_association('Remove comment', f) %>
<% end %>
</div>
CanCanCan 的等价物是:
class Ability
include CanCan::Ability
def initialize(user)
can :destroy, Comment, user: user
end
end
<div class="nested-fields">
<%= f.text_area(:body) %>
<% if can?(:destroy, f.object) %>
<%= link_to_remove_association('Remove comment', f) %>
<% end %>
</div>
【讨论】:
在这两个中,我真的建议学习 Pundit。一开始它有点令人生畏,因为它只是 OOP,但是一旦你需要做任何稍微复杂的事情,CanCanCan 的 DSL 就会让人头疼。以上是关于如何仅更新 rails 6 中 current_user 的嵌套表单属性?的主要内容,如果未能解决你的问题,请参考以下文章
如何毫无例外地选择Array Rails ActiveRecord中的ID