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

通过Ajax与StimulusJS提交表单时,如何同时响应json和turbo_stream?

问题解答

核心原因

Rails 的 respond_to 是根据请求的 Accept 头返回对应格式的响应,一次 HTTP 请求只能返回一种响应格式。同时,render 方法会立即终止响应流程,所以你代码中写的第二个 render 永远不会执行,只会返回第一个定义的格式。

实现需求的可行方案

要同时获取 JSON 数据和 Turbo Stream 的页面更新效果,需要通过变通方式实现,以下是两种常用方案:

方案1:返回 Turbo Stream + 前端事件传递 JSON 数据(推荐)

这种方案只需一次请求,通过在 Turbo Stream 模板中嵌入自定义事件,将 JSON 数据传递给前端处理。

  1. 调整控制器代码(保留两种格式作为备选,实际请求只返回 Turbo Stream):
respond_to do |format|
  if current_model.valid?
    format.turbo_stream { render :success, locals: { data: data } }
    format.json { render json: { data: data, status: 200 } }
  else
    format.turbo_stream { render :errors, locals: { data: data } }
    format.json { render json: { data: data, status: 500 } }
  end
end
  1. 修改 Turbo Stream 模板(比如 success.turbo_stream.erb):
# 先处理页面更新逻辑
<%= turbo_stream.update 'target_element_id', partial: 'success_content' %>

# 嵌入JS发送自定义事件,携带JSON数据
<script>
  document.dispatchEvent(new CustomEvent('form:success', {
    detail: <%= data.to_json.html_safe %>
  }));
</script>
  1. 在 Stimulus 控制器中监听事件并处理 JSON 数据:
// 你的Stimulus控制器
export default class extends Controller {
  connect() {
    document.addEventListener('form:success', this.handleSuccess.bind(this));
    document.addEventListener('form:error', this.handleError.bind(this));
  }

  handleSuccess(event) {
    console.log('获取的JSON数据:', event.detail);
    // 这里可以处理JSON数据的业务逻辑
  }

  handleError(event) {
    console.error('错误数据:', event.detail);
  }
}

方案2:发起两次请求(先拿JSON,再请求Turbo Stream)

这种方案会发起两次请求,适合必须先处理 JSON 再更新页面的场景:

// 用Stimulus的方式提交(替代jQuery Ajax)
submitForm(event) {
  event.preventDefault();
  const form = event.target;
  const formData = new FormData(form);

  // 第一步:请求JSON格式
  fetch(form.action, {
    method: form.method,
    body: formData,
    headers: { 'Accept': 'application/json' }
  })
  .then(res => res.json())
  .then(jsonData => {
    console.log('JSON数据:', jsonData);
    // 第二步:请求Turbo Stream格式更新页面
    return fetch(form.action, {
      method: form.method,
      body: formData,
      headers: { 
        'Accept': 'text/vnd.turbo-stream.html',
        'X-CSRF-Token': Rails.csrfToken()
      }
    });
  })
  .then(res => res.text())
  .then(turboHtml => Turbo.renderStreamMessage(turboHtml))
  .catch(err => console.error('请求失败:', err));
}

总结

HTTP 协议的限制决定了一次请求无法返回两种格式,推荐使用方案1,它更符合 Rails + Turbo + Stimulus 的生态设计,且性能更优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:30:50