如何在另一个控制器的上下文中使用 rails 表单部分而不将 ID 作为隐藏字段传递

问题描述

我正在尝试将评论表单嵌入到 rails Post show 视图中,我可以让它工作的唯一方法是在评论表单中传递这个隐藏字段:

<%= form.hidden_field :post_id,value: "#{params[:id]}" %>

这是我的发布秀操作:

def show
  @comment = Comment.new
end

这是评论创建操作:

def create
  @user = current_user
  @comment = @user.comments.build(comment_params)
end

我尝试将其添加评论创建操作中,但它仍然说缺少帖子 ID:

def create
  @user = current_user
  @post = Post.find(params[:id])
  @comment = @user.comments.build(comment_params).merge(post_id: @post.id)
end

我还尝试将 @post = Post.find(params[:id]) 添加到 Post show 操作,认为如果 rails 具有该变量,那么 Comment create 操作将可以访问 @post.id)。

唯一有效的是在评论表单中添加 post_id 作为隐藏字段,但这似乎很危险,因为恶意用户可以在浏览器中编辑 html。我不知道他们为什么要这样做只是为了更改评论所应用的帖子,但这似乎仍然不是正确的方法

我不想要“嵌套表单”,因为评论是通过帖子表单创建的。

它实际上只是发布展示页面上的一个单独的评论表单。我假设这在 Rails 中很常见,但无法找出“正确”的方法来做到这一点。

解决方法

Rails 的方法是声明一个 nested resource

# config/routes.rb
resources :posts do
  resources :comments,only: [:create]
end

这将创建路由 POST /posts/:post_id/comments,它以 RESTful 方式连接两个资源,并且与将帖子 ID 放在请求正文中相比,使发生的事情变得非常透明。

# app/views/comments/_form.html.erb
<%= form_with(model: [@post,@comment],local: true) do %>
  # don't create a hidden input since the 
  # post id is passed through the URL
<% end %>
# app/views/posts/show.html.erb
<%= render partial: 'comments/form' %>
# app/views/comments/new.html.erb
<%= render partial: 'comments/form' %>
class CommentsController < ApplicationController
  before_action :set_post,only: [:create]

  # POST /posts/1/comments
  def create
    @comment = @post.comments.new(comment_params) do |c|
      c.user = current_user
    end
    if @comment.save
      redirect_to @post,success: 'Comment Created'
    else
      render :new
    end
  end

  private
  def set_post
    @post = Post.find(params[:post_id])
  end
end

唯一有效的是将 post_id 添加为隐藏字段 评论表单,但这似乎很危险,因为恶意用户 可以在浏览器中编辑html。我不知道他们为什么要 这样做只是为了更改评论应用到的帖子, 但这似乎仍然不是正确的方法。

你把问题想错了。如果用户只能对某些帖子发表评论,您需要在您的服务器上强制执行授权(例如使用 Pundit 或 CanCanCan)。

真正糟糕的是在隐藏输入中传递当前用户 ID,因为这让恶意用户很容易以其他用户的身份创建资源。

# This is how you get pwned
<%= form.hidden_field :user_id,value: current_user.id %>

您希望依赖会话存储,因为它已加密且更难以篡改。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...