设置remote: true的Simple Form未触发AJAX,提交后显示空白页
问题
使用ActionCable开发聊天功能时,消息广播正常、接收端能即时渲染消息,但发送端提交消息创建表单后会跳转到空白页(类似常规POST请求的表现)。消息创建方法已返回200状态码,期望停留在当前页面并通过Stimulus插入HTML。怀疑remote: true未触发,表单走了本地提交流程,不确定是否和使用Vite而非Webpacker有关。同时想了解Redis在此场景中的作用。
相关代码
消息创建表单(app/views/chats/show.html.erb)
<%= simple_form_for [@chat, @message], remote: true, html: { class: 'chat__form', data: { action: "turbo:submit-end->chat-subscription#resetForm" } } do |f| %> <%= f.input :content, label: false, placeholder: "Message ##{@name}", input_html: { class: 'chat__form-input' } %> <%= button_tag(class: 'chat__form-button') do %> <%= image_tag('icons/send.svg') %> <% end %> <% end %>
消息控制器create方法(app/controllers/messages_controller.rb)
def create @chat = Chat.find(params[:chat_id]) @message = Message.new(message_params) @message.chat = @chat @message.user = current_user if @message.save ChatChannel.broadcast_to( @chat, render_to_string(partial: "messages/message", locals: {message: @message}) ) head :ok end end
Stimulus控制器(app/javascript/controllers/chat_subscription_controller.js)
import { Controller } from "@hotwired/stimulus" import { createConsumer } from "@rails/actioncable" export default class extends Controller { static values = { chatId: Number } static targets = ['messages', 'form'] connect() { this.channel = createConsumer().subscriptions.create( { channel: 'ChatChannel', id: this.chatIdValue }, { received: data => this.#insertMessageAndScrollDown(data) } ) console.log(`Subscribed to the chat with the id ${this.chatIdValue}.`) console.log(this.messagesTarget) } #insertMessageAndScrollDown(data) { this.messagesTarget.insertAdjacentHTML('beforeend', data) this.messagesTarget.scrollTo(0, this.messagesTarget.scrollHeight) } resetForm(event) { event.preventDefault() event.target.reset() } disconnect() { console.log('Unsubscribed from the chat') this.channel.unsubscribe() } }
解决方案
修正
remote: true的使用问题
Rails 7+默认用Turbo替代UJS,remote: true已不再生效。Turbo会自动处理表单提交,但需要确保提交行为不会触发页面跳转:- 移除表单上的
remote: true属性; - 将表单的
data-turbo设为false,改用手动AJAX提交逻辑,确保提交后不刷新页面; - 或者监听
turbo:submit-start事件并阻止默认行为,在Stimulus中手动发送请求。
- 移除表单上的
调整Stimulus的表单重置逻辑
当前resetForm方法绑定的turbo:submit-end事件无法阻止页面跳转,需要提前拦截提交行为:// 在Stimulus控制器中添加拦截提交的方法 submitForm(event) { event.preventDefault() // 手动发送AJAX请求提交表单数据 fetch(event.target.action, { method: 'POST', headers: { 'Accept': 'text/plain', 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content }, body: new FormData(event.target) }).then(() => { event.target.reset() }) }然后在表单的
data-action中改为submit->chat-subscription#submitForm。Vite配置检查
确保Vite正确加载Turbo和Stimulus,在entrypoints/application.js中包含:import "@hotwired/turbo-rails" import "controllers"确认Vite Rails插件已正确配置,保证相关JS文件被打包加载。
Redis在ActionCable中的作用
- 跨服务器消息共享:单服务器部署时ActionCable可用内存存储广播消息,但多服务器场景下,内存无法跨节点共享。Redis作为分布式消息中间件,能让所有服务器节点同步广播内容,确保连接到不同服务器的客户端都能收到消息。
- 订阅状态管理:Redis帮助ActionCable跟踪所有活跃的频道订阅关系,保证消息能精准推送给所有订阅对应频道的客户端。
- 提升可靠性:相比内存存储,Redis可配置持久化,避免服务器重启时丢失未发送的消息,增强系统稳定性。
内容的提问来源于stack exchange,提问作者Lisbeth Purrucker
相关产品推荐
相关产品推荐

