使用Redis时ActionCable广播无响应、received回调不触发如何解决
问题根因
- 表单默认同步提交触发页面重载,WebSocket连接随页面刷新中断,无法接收广播回调
- 广播接收后未实现DOM插入逻辑,即使收到消息也不会更新页面
- 本地Redis服务未启动可能导致广播无法正常分发
修复步骤
步骤1:修改表单为异步提交
修改_chatbox.html.erb中表单配置,添加remote: true禁用默认同步提交,同时给消息容器添加唯一ID方便DOM操作:
<div class="ui feed" id="messages-container"> <%=render @messages%> </div> <!-- 表单部分修改 --> <%= form_for(@message, html: {class: 'ui reply form'}, role: 'form', url: message_path, remote: true) do |f|%>
步骤2:调整控制器响应逻辑
修改messages_controller.rb的create方法,添加异步请求响应处理,可按需传递更多展示用字段:
def create message = current_user.messages.build(message_params) if message.save ActionCable.server.broadcast("chatroom_channel", { body: message.body, user: current_user.username }) # 返回空成功响应,避免不必要的页面渲染 head :ok end end
步骤3:实现消息接收后的DOM更新逻辑
修改chatroom_channel.js的received方法,完成消息插入、输入框清空等操作,HTML结构需和你现有_message.html.erb局部视图的结构保持一致:
import consumer from "./consumer" consumer.subscriptions.create("ChatroomChannel", { connected() { console.log('chatroom connected working') }, disconnected() {}, received(data) { console.log('received data', data) const messagesContainer = document.getElementById('messages-container') const newMessageEl = document.createElement('div') newMessageEl.className = 'event' newMessageEl.innerHTML = ` <div class="content"> <div class="summary"> ${data.user} <span class="date">刚刚</span> </div> <div class="extra text">${data.body}</div> </div> ` messagesContainer.appendChild(newMessageEl) // 自动滚动到聊天框底部 messagesContainer.scrollTop = messagesContainer.scrollHeight // 清空输入框 document.querySelector('input[name="message[body]"]').value = '' } });
步骤4:验证广播分发服务状态
如果使用Redis适配器,先确认本地Redis服务已启动,终端执行redis-cli ping返回PONG即为正常。
若暂时不想启动Redis,可修改cable.yml开发环境配置为内置async适配器:
development: adapter: async
内容的提问来源于stack exchange,提问作者Ale Yanczuk
相关产品推荐
相关产品推荐

