You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 7中Turbo Stream局部渲染异常:样式错乱、帖子重复

问题根源

你遇到的样式错乱、帖子重复问题,核心原因是用Turbo Stream替换单个帖子的Turbo Frame时,却渲染了包含所有帖子的_posts.html.erb局部视图——这会把目标Frame的内容替换成完整的帖子列表,自然导致重复渲染和样式混乱。


修复步骤

1. 拆分局部视图,抽离单条帖子模板

创建app/views/shared/_post.html.erb,把原_posts.html.erb中单个帖子的内容移进去:

<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 "Like", 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>

然后修改原_posts.html.erb,只负责循环渲染每个帖子的Turbo Frame并引用新的单帖局部:

<div class="container col-sm-4 mx-auto mt-4">
    <% posts.each do |post| %>
        <%= turbo_frame_tag dom_id(post) do %>
            <%= render 'shared/post', post: post %>
        <% end %>
    <% end %> 
</div>

2. 修改LikesController,只更新当前操作的帖子

在create和destroy方法里,不要渲染整个帖子列表,只渲染当前操作的单个帖子局部,替换对应的Turbo Frame:

class LikesController < ApplicationController
    before_action :fetch_post

    def create
        @like = Like.find_or_initialize_by(likeable: @post, user: current_user)
        if @like.save
            # 重新加载帖子,确保点赞数是最新的
            @post.reload
            render turbo_stream: turbo_stream.replace(
                dom_id(@post),
                partial: 'shared/post',
                locals: { post: @post }
            )
        end
    end

    def destroy
        @like = current_user.likes.find_by(likeable: @post)
        if @like.destroy
            @post.reload
            render turbo_stream: turbo_stream.replace(
                dom_id(@post),
                partial: 'shared/post',
                locals: { post: @post }
            )
        end
    end

    private

    def like_params
        params.permit() # 若无需额外参数,用permit()规范写法
    end

    def fetch_post
        @post = Post.find(params[:id]) # 用find替代find_by,找不到直接返回404,符合Rails惯例
    end
end

额外优化点

  • 调用@post.reload确保拿到最新的点赞计数,避免缓存旧数据
  • 修正like_params的写法,避免语法错误
  • 把fetch_post里的find_by改成find,增强错误处理的合理性

内容的提问来源于stack exchange,提问作者Yash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 12:06:02