提问人:mutebi godfrey 提问时间:11/11/2023 最后编辑:Alexmutebi godfrey 更新时间:11/16/2023 访问量:118
如何使用 turbo 帧和流递归渲染部分
How to render partials recursively with turbo frames and stream
问:
- 您好,我对 Turbo Streams 和 Frames 比较陌生,我目前面临着使用 Turbo Frames 和 Streams 渲染评论回复的问题。
让我解释一下我的设置。我有一个评论模型,我使用同一个表来包含评论及其各自的回复。以下是我如何实现它
- 下面是我的
comment.rb
class Comment < ApplicationRecord
belongs_to :post
belongs_to :user
has_many :likes, as: :likeable
scope :ordered, -> { order(id: :desc) }
belongs_to :parent, class_name: 'Comment', optional: true
has_many :replies, class_name: 'Comment', foreign_key: :parent_id, dependent: :destroy
validates :body, presence: true
end
下面是我的帖子显示页面,我想在其中呈现评论,所有评论来自
<%= turbo_frame_tag "comments" do%> <%= render @comments, post: @post, comment: @comment %> <% end %>
- 下面是我的评论部分,我希望每个父评论的回复都以递归方式嵌套在其下
<%= turbo_frame_tag comment do%> <div class=""> <p class="mt-4 text-gray-500 dark:text-gray-400"><%= comment.body %></p> </div> <%= turbo_frame_tag dom_id(Comment.new) do%> <%= render "comments/like_button", comment: comment%> <% end %> <% if comment.replies.any? %> <% comment.replies.each do |reply| %> <div class="ml-4"> <%= turbo_frame_tag nested_dom_id(comment, "replies") do%> <%= render 'comments/comment', comment: reply %> <% end %> </div> <% end %> <% end %> </div> <% end %>
app/views/comments/create_turbo.stream.erb
<%= turbo_stream.update Comment.new, "" %> <% if @comment.parent_id.nil? %> <%= turbo_stream.prepend "comments", @comment%> <% else %> <% @comment.replies.each do |reply| %> <%= turbo_stream.prepend nested_dom_id(@comment, "replies") do%> <%= render 'comments/comment', comment: reply %> <% end %> <% end %> <% end %>
- 问题是,子评论只有在我手动刷新页面后才能很好地嵌套显示,这不是我想要的情况。我想要的是,当我创建一个回复时,我希望它呈现在其父级下,而无需刷新页面。
- 任何帮助将不胜感激
答:
0赞
Alex
11/11/2023
#1
喜欢这个:
# app/views/comments/index.html.erb
<%= link_to "New comment", new_comment_path, data: {turbo_frame: :new_comment} %>
<%= turbo_frame_tag :new_comment, class: "contents" %>
<%= tag.div id: :comments do %>
<%= render @comments.where(parent_id: nil) %>
<% end %>
# app/views/comments/_comment.html.erb
<%= tag.div id: dom_id(comment) do %>
<%= comment.body %>
<%= link_to "Reply", new_comment_path(parent_id: comment),
data: {turbo_frame: dom_id(comment, :new_comment)} %>
<%= tag.div id: dom_id(comment, :comments), class: "pl-4" do %>
<%= render comment.replies %>
<% end %>
<%= turbo_frame_tag comment, :new_comment, class: "contents" %>
<% end %>
# app/views/comments/new.html.erb
# grab parent_id from url params
<% @comment.parent_id ||= params[:parent_id] %>
<%= turbo_frame_tag *[@comment.parent, :new_comment].compact, class: "contents" do %>
<%= render "form", comment: @comment %>
<% end %>
# app/views/comments/_form.html.erb
<%= form_with model: comment, class: "contents" do |f| %>
<%= f.hidden_field :parent_id %>
<%= f.text_area :body, placeholder: :comment %>
<%= f.submit class: "btn-primary" %>
<% end %>
# app/controllers/comments_controller.rb
def create
@comment = Comment.new(comment_params)
respond_to do |format|
if @comment.save
format.turbo_stream do
if @comment.parent
render turbo_stream: [
# remove reply form
turbo_stream.update(helpers.dom_id(@comment.parent, :new_comment)),
# add new reply under the corresponding parent comment
turbo_stream.append(helpers.dom_id(@comment.parent, :comments), @comment),
]
else
render turbo_stream: [
turbo_stream.update(:new_comment),
turbo_stream.append(:comments, @comment),
]
end
end
format.html { redirect_to comments_url, notice: "Created." }
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
请注意,turbo-rails 已更新为生成与以下相同的 id:
https://github.com/hotwired/turbo-rails/pull/476v1.5.0
turbo_frame_tag
dom_id
在执行此操作之前:v1.5.0
<%= turbo_frame_tag :new_comment, comment, class: "contents" %>
<%= turbo_frame_tag *[:new_comment, @comment.parent].compact, class: "contents" do %>
#...
结果:
<div>
<a data-turbo-frame="new_comment" href="/comments/new">New comment</a>
<turbo-frame class="contents" id="new_comment"></turbo-frame>
<div id="comments">
<div id="comment_39">
first comment
<a data-turbo-frame="new_comment_comment_39" href="/comments/new?parent_id=39">Reply</a>
<div id="comments_comment_39" class="pl-4">
<div id="comment_41">
first reply
<a data-turbo-frame="new_comment_comment_41" href="/comments/new?parent_id=41">Reply</a>
<div id="comments_comment_41" class="pl-4"></div>
<turbo-frame class="contents" id="new_comment_comment_41"></turbo-frame>
</div>
<div id="comment_42">
second reply
<a data-turbo-frame="new_comment_comment_42" href="/comments/new?parent_id=42">Reply</a>
<div id="comments_comment_42" class="pl-4">
<div id="comment_43">
first reply to second reply
<a data-turbo-frame="new_comment_comment_43" href="/comments/new?parent_id=43">Reply</a>
<div id="comments_comment_43" class="pl-4"></div>
<turbo-frame class="contents" id="new_comment_comment_43"></turbo-frame>
</div>
</div>
<turbo-frame class="contents" id="new_comment_comment_42"></turbo-frame>
</div>
</div>
<turbo-frame class="contents" id="new_comment_comment_39"></turbo-frame>
</div>
<div id="comment_40">
second comment
<a data-turbo-frame="new_comment_comment_40" href="/comments/new?parent_id=40">Reply</a>
<div id="comments_comment_40" class="pl-4"></div>
<turbo-frame class="contents" id="new_comment_comment_40"></turbo-frame>
</div>
</div>
</div>
评论
0赞
mutebi godfrey
11/14/2023
我试过这个,但子评论只出现在顶部,但我希望它们嵌套在父项下
0赞
Alex
11/14/2023
@mutebigodfrey查看结果的屏幕截图^。我特别在底部和相应的家长评论下附加了新的回复:turbo_stream.append(helpers.dom_id(@comment.parent, :comments), @comment)
0赞
mutebi godfrey
11/16/2023
#2
- I made few changes to make it work
```
<% if @comment.parent_id.nil? %>
<%= turbo_stream.prepend "comments" do %>
<%= render @comment %>
<% end %>
<% else %>
<%= turbo_stream.after dom_id(@comment.parent) do %>
<div class="ml-4">
<%= render @comment %>
</div>
<% end %>
<% end %>
```
- now i can have comments rendered recursively
评论
0赞
mutebi godfrey
11/16/2023
现在我可以递归嵌套注释了
评论