我对 Rails 很陌生。我发现这个奇怪的问题与turbo_frame和多种新形式有关。
我有一个带有
Post
的模型 comments
,当我尝试加载多个表单时,即使我指定使用 Comment.new,一个表单中的值也会出现在其他表单上
###posts/index.html.erb
<div id="posts">
<% @posts.each do |post| %>
<div class="post">
<%= turbo_frame_tag dom_id(post) do %>
<%= render 'posts/show', post: post)%>
<% end %>
</div>
<hr>
<% end %>
</div>
### posts/_show.html.erb
<% post.comments.each do |comment| %>
<%= render "comments/comment", post: post, comment: comment %>
<% end %>
<%= turbo_frame_tag "comments_#{post.id}" do %>
<% end %>
<%= render "comments/add_new_comment", post: post, comment: Comment.new %>
### _add_new_comment.html.erb
<%= turbo_frame_tag "comments_new#{post.id}" do %>
<%= link_to "Add comment", open_create_new_comment_path(post) %>
<% end %>
### comments/_comment.html.erb
<%= turbo_frame_tag dom_id(comment) do %>
<div>
<%= comment.body %>
<div>
<%= link_to 'Edit', edit_post_comment_path(comment.post, comment) %>
<%= link_to 'Delete', post_comment_path(comment.post, comment),
method: :delete,
data: { confirm: 'Are you sure?', turbo_method: :delete } %>
</div>
</div>
<% end %>
### comments/_form.html.erb
<%= turbo_frame_tag "new_comment_form_#{post.id}" do %>
<%= form_with(model: [post, Comment.new]) do |form| %>
<%= form.rich_text_area :body %>
<%= form.hidden_field :post_id, value: post.id %>
<%= form.submit "Submit", data: { disable_with: "Submitting..." } %>
<% end %>
<% end %>
最后是控制器
class CommentsController < ApplicationController
before_action :set_post
before_action :set_comment, only: [:edit, :update, :destroy]
def edit
render turbo_stream: turbo_stream.replace("comment_#{params[:id]}", partial: "comments/edit_form", locals: {post: @post, comment: @comment})
end
def open_create_new
render turbo_stream: turbo_stream.replace("comments_new#{@post.id}", partial: "comments/form", locals: {post: @post, comment: Comment.new})
end
def create
@comment = Comment.new(comment_params)
if @comment.save
respond_to do |format|
format.turbo_stream do
render turbo_stream: [
turbo_stream.prepend("comments_#{@post.id}", partial: "comments/comment", locals: {comment: @comment}),
turbo_stream.replace("new_comment_form_#{@post.id}", partial: "comments/add_new_comment", locals: {post: @post})
]
end
end
else
respond_to do |format|
format.turbo_stream { render turbo_stream:turbo_stream.replace("new_comment_form_#{@post.id}", partial: "comments/add_new_comment", locals: {post: @post})}
end
end
end
# PATCH/PUT /comments/1 or /comments/1.json
def update
if @comment.update(comment_params)
render turbo_stream: turbo_stream.replace("edit_comment_form_#{@comment.id}", partial: "comments/comment", locals: {comment: @comment})
else
render turbo_stream: turbo_stream.replace("edit_comment_form_#{@comment.id}", partial: "comments/comment", locals: {comment: @comment})
end
end
# DELETE /comments/1 or /comments/1.json
def destroy
@comment.destroy
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.remove("comment_#{params[:id]}")
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
@comment = Comment.find(params[:id])
end
def set_post
@post = Post.friendly.find_by(slug: params[:post_id])
end
# Only allow a list of trusted parameters through.
def comment_params
params.require(:comment).permit(:body, :post_id, :parent_id)
end
end
奇怪的是,每个表单都能完美地单独工作,但是如果我从帖子 1 加载表单,输入一些文本,然后打开表单向其他帖子添加评论,则文本与我在表单 1 中输入的文本相同,当我尝试提交表单,日志显示正文为空。
想法?为什么当我将所有内容放入
locals
并使用 Comment.new
时,其中一个的内容会添加到其他内容中
这是一个富文本字段的javascript问题,您需要为页面上的每个富文本字段拥有唯一的ID,您可以使用
:namespace
助手的form_with
选项:
<%= form_with model: [post, Comment.new], namespace: dom_id(post) do |form| %>
<%= form.rich_text_area :body %>
<% end %>
<input type="hidden" name="comment[body]" id="post_2_comment_body_trix_input_comment" autocomplete="off">
<!-- namespace: ^^^^^^ -->
删除
turbo_frame_tag
s,你实际上并没有使用它们:
<!-- app/views/posts/index.html.erb -->
<div id="posts">
<%= render @posts %>
</div>
<!-- app/views/posts/_post.html.erb -->
<div id="<%= dom_id post %>">
<!-- will append post's comments here -->
<div id="<%= dom_id post, :comments %>">
<%= render post.comments %>
</div>
<!-- will update with new comment form then back to link -->
<div id="<%= dom_id post, :new_comment %>">
<%= link_to "Add comment", new_post_comment_path(post), data: {turbo_stream: true} %>
</div>
</div>
<!-- app/views/comments/_form.html.erb -->
<%= form_with model: [post, Comment.new], namespace: dom_id(post) do |form| %>
<%= form.rich_text_area :body %>
<%= form.submit "Submit", data: {turbo_submits_with: "Submitting..."} %>
<% end %>
<!-- app/views/comments/_comment.html.erb -->
<div id="<%= dom_id comment %>">
<%= comment.body %>
<div>
<%= link_to "Edit", edit_post_comment_path(comment.post, comment), data: {turbo_stream: true} %>
<%= link_to "Delete", post_comment_path(comment.post, comment), data: {turbo_confirm: "Are you sure?", turbo_method: :delete} %>
</div>
</div>
# app/controller/comments_controller.rb
def new
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.update(
[@post, :new_comment],
partial: "comments/form",
locals: {post: @post, comment: Comment.new}
)
end
end
end
def create
@comment = @post.comments.new(comment_params)
if @comment.save
respond_to do |format|
format.turbo_stream do
render turbo_stream: [
turbo_stream.append(
[@post, :comments],
partial: "comments/comment",
locals: {comment: @comment}
),
turbo_stream.update(
[@post, :new_comment],
helpers.link_to("Add comment", new_post_comment_path(@post), data: {turbo_stream: true})
)
]
end
end
else
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.update(
[@post, :new_comments],
partial: "comments/form",
locals: {comment: @comment, post: @post}
)
end
end
end
end
def edit
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.update(
@comment,
partial: "comments/form",
locals: {comment: @comment, post: @post}
)
end
end
end
def update
respond_to do |format|
if @comment.update(comment_params)
format.turbo_stream do
render turbo_stream: turbo_stream.update(@comment)
end
else
format.turbo_stream do
render turbo_stream: turbo_stream.update(
@comment,
partial: "comments/form",
locals: {comment: @comment, post: @post}
)
end
end
end
end
def destroy
@comment.destroy
respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.remove(@comment) }
end
end