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

Rails 7 Turbo Stream无法传递current_user问题求助

Rails Turbo 流式消息删除按钮不显示问题

问题现象

系统中每个Applicant关联多条Message,双方用户可通过Applicant互发消息,消息流基础功能正常。但仅消息发布者可删除消息的逻辑存在异常:页面初始加载或刷新时删除按钮显示正常,通过Turbo流式加载的新消息却不显示删除按钮。

核心问题分析

  1. Turbo流渲染时无法自动继承页面的@is_owner实例变量,而消息Partial依赖该变量判断是否显示删除按钮。
  2. 同时使用了两种Turbo广播逻辑(控制器手动渲染+模型after_save_commit广播),导致逻辑冲突,且模型广播在后台Job执行,无法访问请求上下文(如current_user)。

解决方案

1. 移除重复的模型端广播逻辑

删除模型中与控制器重复的Turbo广播代码,避免逻辑冲突:

# app/models/message.rb
class Message < ApplicationRecord
  # 移除该行重复广播逻辑
  # after_save_commit -> { broadcast_append_later_to "applicant_messages_#{self.applicant_id}", partial: "messages/message", locals: { message: self }, target: "messages" }
  after_destroy_commit -> { broadcast_remove_to "applicant_messages_#{self.applicant_id}", target: "message_#{self.id}" }
end

2. 在控制器Turbo流渲染中传递身份上下文

修改MessageController#create,计算当前用户的is_owner身份并显式传递给Partial:

# app/controllers/message_controller.rb
class MessageController < ApplicationController
  before_action :authenticate_user!
  def create
    @message = Message.new(message_params)
    applicant = @message.applicant
    # 计算当前用户是否为项目所有者
    @is_owner = current_user == applicant.project.user

    respond_to do |format|
      if @message.save
        format.turbo_stream do
          render turbo_stream: turbo_stream.append(
            "messages", # 对应页面中<div id="messages">的target ID
            partial: "messages/message",
            locals: { message: @message, is_owner: @is_owner } # 传递身份变量到Partial
          ), notice: 'Message was successfully created.'
        end
        format.json { render :show, status: :created, message: @message }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @message.errors, status: :unprocessable_entity }
      end
    end
  end
end

3. 修改Partial使用传入的局部变量

将Partial中依赖的@is_owner实例变量改为传入的is_owner局部变量:

# app/views/messages/_message.html.erb
<%= turbo_frame_tag dom_id(message) do %>
  <p>
    <%= message.is_owner == true ? "#{message.applicant.project.user.first_name}" : "#{message.applicant.user.first_name}" %> (<%= message.id %>): 
    <%= message.body %>
    <%# 使用传入的is_owner变量判断是否显示删除按钮 %>
    <% if message.is_owner == is_owner %>
      [<%= link_to "delete", message_delete_path(message.hashid), method: :delete, data: {turbo_method: :delete} %>]
    <% end %>
  </p>
<% end %>

4. 统一初始渲染的变量传递

修改show.html.erb中初始渲染消息列表的代码,确保传递is_owner变量:

# app/views/applicants/show.html.erb
<div class="container">
  <div>
    <%= turbo_stream_from "applicant_messages_#{@applicant.id}" %>
    <div id="messages">
      <%# 渲染消息列表时传递is_owner %>
      <%= render @messages, is_owner: @is_owner %>
    </div>
  </div>
</div>

<!-- 表单部分保持不变 -->
<div class="container">
  <%= form_for @message, url: message_create_path(@applicant.hashid),data: { controller: "message", action: "turbo:submit-end->message#reset"}, method: :post, html: {id: "message_form"}, remote: true do |f| %>
    <%= f.hidden_field :is_owner, value: @is_owner %>
    <%= f.hidden_field :applicant_id, value: @applicant.id %>
    <%= f.text_field :body, autofocus: true, autocomplete: 'off', placeholder: "Enter message", id: "message_body", class: "form-control", data: { turbo_stream: true } %>
    <%= f.submit 'Post message', class: 'btn btn-primary d-inline', data: {disable_with: "Working on it..."}  %>
  <% end %>
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 18:35:17