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

Turbo Streams中after_destroy_commit结合broadcast_replace_later_to报错问题

解决Turbo Streams好友请求销毁时的反序列化错误问题

问题分析

使用broadcast_replace_later_to时,延迟任务执行前FriendRequest对象已被销毁,ActiveJob反序列化时找不到对应数据库记录,抛出ActiveJob::DeserializationError;改用同步的broadcast_replace_to后仅首个回调生效,是因为之前依赖已销毁的friend_request实例传递状态,导致后续广播逻辑出错。

解决方案

1. 重构视图partial,移除对friend_request实例的依赖

修改app/views/users/_friend_request_form.html.erb,通过当前登录用户和目标用户的关联关系动态渲染按钮,不再依赖传入的friend_request对象:

<% if logged_in_user.friend_requests_sent.exists?(receiver: user) %>
  <%= button_to "取消好友请求", friend_request_path(logged_in_user.friend_requests_sent.find_by(receiver: user)), method: :delete %>
<% elsif logged_in_user.friend_requests_received.exists?(sender: user) %>
  <%= button_to "接受请求", accept_friend_request_path(logged_in_user.friend_requests_received.find_by(sender: user)), method: :patch %>
  <%= button_to "拒绝请求", friend_request_path(logged_in_user.friend_requests_received.find_by(sender: user)), method: :delete %>
<% elsif logged_in_user.friends.include?(user) %>
  <%= button_to "解除好友关系", friend_path(user), method: :delete %>
<% else %>
  <%= button_to "添加好友", friend_requests_path, method: :post, params: { friend_request: { receiver_id: user.id } } %>
<% end %>

2. 调整模型中的广播逻辑,使用同步广播并传递有效实例

修改app/models/friend_request.rb,移除对self(已销毁的FriendRequest实例)的传递,改用同步广播,确保销毁时仍能正确获取发送者和接收者的实例:

after_create_commit do 
  broadcast_friend_request_updates
end

after_destroy_commit do 
  broadcast_friend_request_updates
end

private

def broadcast_friend_request_updates
  # 给请求发送者的页面广播,更新接收者的操作按钮
  broadcast_replace_to "user_#{sender.id}_friend_updates",
    target: dom_id(user: receiver),
    partial: "users/friend_request_form",
    locals: { logged_in_user: sender, user: receiver }

  # 给请求接收者的页面广播,更新发送者的操作按钮
  broadcast_replace_to "user_#{receiver.id}_friend_updates",
    target: dom_id(user: sender),
    partial: "users/friend_request_form",
    locals: { logged_in_user: receiver, user: sender }
end

3. 确保视图中正确包裹Turbo Frame

在渲染用户列表或用户详情的视图中,将好友请求按钮包裹在对应Turbo Frame内:

<%= turbo_frame_tag dom_id(user: user) do %>
  <%= render "users/friend_request_form", logged_in_user: current_user, user: user %>
<% end %>

4. 在页面中订阅对应流

在用户的页面(比如首页或用户列表页)添加流订阅:

<%= turbo_stream_from "user_#{current_user.id}_friend_updates" %>

关键说明

  • 同步广播broadcast_replace_to在after_destroy_commit回调中仍可访问内存中的sender和receiver实例,不会触发数据库查询错误
  • 视图通过关联查询动态判断状态,彻底避免依赖已销毁的FriendRequest对象
  • 每个用户订阅专属的好友更新流,确保广播仅推送给目标用户的页面

内容的提问来源于stack exchange,提问作者Adrian-y

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 00:05:43