Search code examples
ruby-on-railsruby-on-rails-7hotwire-railsturbo-frames

How to render partials recursively with turbo frames and stream


  • Hello, I'm relatively new to Turbo Streams and Frames, and I'm currently facing an issue with rendering replies to comments using Turbo Frames and Streams.

Let me explain my setup. I have a Comment model, and I've utilized the same table to include both comments and their respective replies. Below is how I've implemented it

  • Below is my 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
  • below is my posts show page where where i want to render comments all comments from

        <%= turbo_frame_tag "comments" do%>
          <%= render @comments, post: @post, comment: @comment %>
        <% end %>
    

    -Below is my comment partial where i want every parent comment to have its replies nested under it recursively

    <%= 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 %>
    
    • The problem is , the child comments only show up well nested after i refresh the page manually, which is not the case i want. what i want is that when i create a reply , i want it to get rendered under its parent without page refresh.
    • Any help will be appreciated

Solution

  •  - 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