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

