ruby-on-railsruby-on-rails-7hotwire-railsturbo

Partial render with turbo stream is not working in rails 7


_posts.html.erb

    <div class="container col-sm-4 mx-auto mt-4">
        <% posts.each do |post| %>
        <%= turbo_frame_tag dom_id(post) do %>
            <div class="card text-center bg-info" style="width: 18rem;">
                <%= image_tag file_path(post.medias.first), class: "rounded mx-auto d-block" %>
                <h6 class="card-subtitle mb-2 text-body-secondary mt-2">by <%= post.user.first_name %> <%= post.user.last_name%> </h6>
                <div class="card-body">
                    <p class="card-text"><%= post.description %></p>
                    <%= link_to "View Post", post_path(post), class: "btn btn-dark" %>
                </div>
                <div class="card-footer text-body-secondary">
                    <%= time_ago_in_words(post.created_at) %> ago
                </div>
                <div class="row justify-content-between mb-2">
                    <% if current_user_post_like?(post) %>
                        <div class="col-sm-3"> 
                            <%= post.likes.count %>
                            <%= link_to "Unlike", likes_path({id: post}), data: {turbo_stream: true, turbo_method: :delete} %>
                        </div>
                    <% else %>
                        <div class="col-sm-3"> 
                            <%= post.likes.count %>
                            <%= link_to "Liked", likes_path({id: post}), data: {turbo_stream: true, turbo_method: :post} %>
                        </div>
                    <% end %>
                    <div class="col-sm-3"> 1 </div>
                    <div class="col-sm-3"> 1 </div>
                </div>
            </div>
            <% end %>

        <% end %> 
    </div>

likes_controller.rb

class LikesController < ApplicationController
    before_action :fetch_post

    def create
        @like = Like.find_or_initialize_by(likeable: fetch_post, user: current_user)
        if @like.save
            @posts = Post.all
            render turbo_stream: turbo_stream.replace(
                @post,
                partial: 'shared/posts',
                locals: { posts: @posts }
                )
        end
    end

    def destroy
        @like = current_user.likes.find_by(likeable: @post)
        if @like.destroy
            @posts = Post.all

            render turbo_stream: turbo_stream.replace(
                @post,
                partial: 'shared/posts',
                locals: { posts: @posts }
                )
        end
    end

    private

    def like_params
        params.require
    end

    def fetch_post
        @post = Post.find_by(id: params[:id])
    end
end

pages_controller.rb

class PagesController \< ApplicationController
    def index
        @posts = Post.all
    end
end

I am getting error while render partial with turbo_stream , designs are getting broken, duplicates posts are showing. i am fetching all posts in pages controllers and rendering the _posts partial after that when i clicked on like it should get update with turbo_stream enter image description here


Solution

  • You're replacing one target post with all posts including the container, which ends up nesting and duplicating everything.

    # app/views/shared/_posts.html.erb -->
    
    <%= render @posts %>
    

    I'm not sure if you actually need turbo frame here, it's not required for this:

    # app/views/posts/_post.html.erb
    
    # this is your target that you want to replace
    #               vvvvvvvvvvvv
    <%= tag.div id: dom_id(post) do %>
      # TODO: your post layout
    <% end %>
    

    Then in your controller, when you're replacing a post you have to render just that post:

    render turbo_stream: turbo_stream.replace(
      @post,                  # this implicitly generates target id with `dom_id(@post)`
      partial: "posts/post",  # which is replaced with this partial
      locals: {post: @post}
    )
    
    # can be shortened to
    render turbo_stream: turbo_stream.replace(@post)
    

    Another similar example: https://stackoverflow.com/a/74508675/207090