问题描述
我正在尝试将评论表单嵌入到 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
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 %>
您希望依赖会话存储,因为它已加密且更难以篡改。