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
相关产品推荐
相关产品推荐

