mcpField
T
turbo-fetch

turbo-fetch

github.com/rolemodel开发7123 次安装2 天前更新
代码仓库

关于 turbo-fetch

介绍在 Rails 中结合 Turbo Streams 和 Stimulus 动态更新表单字段的模式,适合需要联动字段或条件表单区块的开发者,无需重新加载页面。

主要功能

  1. 01通过 PATCH 刷新字段
  2. 02使用 Turbo Stream 更新 DOM
  3. 03由 Stimulus 触发请求
  4. 04集合与成员路由模式

适用场景

  1. 01选择后刷新下拉选项
  2. 02显示条件表单区块
  3. 03无需整页重载即可更新表单

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rolemodel/rolemodel-skills --skill turbo-fetch

安装后在 Claude Code 中输入/turbo-fetch确认已加载。

详细介绍

Turbo Fetch 技能

本文档介绍 turbo fetch 模式,说明如何使用 Turbo Streams 和 Stimulus,根据用户输入动态更新表单字段。

适用场景

在以下情况下使用 turbo fetch:

  • 根据另一个字段的选项更新表单选项
  • 动态显示或隐藏条件字段
  • 无需重新加载整个页面即可刷新表单的部分内容
  • 实现级联下拉菜单或依赖字段

模式概览

turbo fetch 模式由四个组件组成:

  1. 路由 - 添加 turbo_fetch 端点的路由关注点
  2. 控制器操作 - 准备数据并渲染 turbo streams 的后端操作
  3. Stimulus 控制器 - 触发 PATCH 请求的前端控制器
  4. Turbo Stream 视图 - 更新指定 DOM 元素的模板

实现步骤

1. 添加路由关注点(如果尚未添加)

在 config/routes.rb 中,确保存在 turbo_fetch 关注点:

concern :turbo_fetch do
  patch :turbo_fetch, on: :collection
end

然后将其应用到你的资源:

resources :materials, concerns: %i[turbo_fetch]

这会创建一条路由:PATCH /materials/turbo_fetch

2. 实现控制器操作

在你的控制器中添加 turbo_fetch 操作:

class MaterialsController < ApplicationController
  def turbo_fetch
    @material = authorize Material.new(material_params)
    # The view will handle the turbo stream responses
  end

  private

  def material_params
    params.require(:material).permit(:type, :substance, ...)
  end
end

要点:

  • 使用提交的参数创建一个新实例(不会保存到数据库)
  • 如有需要,执行授权检查
  • 该实例将在 turbo stream 视图中用于确定要更新的选项
3. 创建 Turbo Stream 视图

创建 app/views/[resource]/turbo_fetch.turbo_stream.slim:

= simple_form_for @material do |f|
  = turbo_stream.update 'substance-field' do
    = f.input :substance, collection: @material.substances
  = turbo_stream.replace 'material_details', partial: dimension_fields_partial_path, locals: { f: }

可用的 turbo stream 操作:

  • turbo_stream.update - 替换元素内部的内容
  • turbo_stream.replace - 替换整个元素
  • turbo_stream.append - 在末尾添加内容
  • turbo_stream.prepend - 在开头添加内容
  • turbo_stream.remove - 移除一个元素
4. 使用 Stimulus 控制器设置表单

将 Stimulus 控制器添加到表单中:

= simple_form_for resource, data: { controller: 'turbo-fetch', turbo_fetch_url_value: turbo_fetch_materials_url } do |f|
  .form-row
    = f.input :type, input_html: { data: { action: "turbo-fetch#perform" } }

  #substance-field.flexible
    = f.input :substance, collection: f.object.substances

  #material_details
    = render dimension_fields_partial_path, f: f

关键属性:

  • data-controller="turbo-fetch" - 激活 Stimulus 控制器
  • data-turbo-fetch-url-value - 要发送 PATCH 请求的 URL(默认为表单操作地址 + /turbo_fetch)
  • data-action="turbo-fetch#perform" - 在字段更改时触发 fetch
5. 确认 Stimulus 控制器存在

turbo_fetch_controller.js 应位于 app/javascript/controllers/turbo_fetch_controller.js:

import { Controller } from '@hotwired/stimulus'
import { patch } from '@rails/request.js'

export default class extends Controller {
  static values = { url: String, count: Number }

  async perform({ params: { url: urlParam, query: queryParams } }) {
    const body = new FormData(this.element)

    if (queryParams) Object.keys(queryParams).forEach(key => body.append(key, queryParams[key]))

    const response = await patch(urlParam || this.urlValue, { body, responseKind: 'turbo-stream' })
    if (response.ok) this.countValue += 1
  }
}

代码库中的示例

Materials 示例

路由:

resources :materials, concerns: %i[duplication turbo_fetch]

控制器:

def turbo_fetch
  @material = authorize Material.new(material_params)
end

视图(turbo_fetch.turbo_stream.slim):

= simple_form_for @material do |f|
  = turbo_stream.update 'substance-field' do
    = f.input :substance, collection: @material.substances, as: :tom_select, allow_create: true
  = turbo_stream.replace 'material_details', partial: dimension_fields_partial_path, locals: { f: }

表单:

= simple_form_for resource, data: { controller: 'turbo-fetch', turbo_fetch_url_value: turbo_fetch_materials_url } do |f|
  = f.input :type, input_html: { data: { action: "turbo-fetch#perform" } }

  #substance-field.flexible
    = f.input :substance, collection: f.object.substances

  #material_details
    = render dimension_fields_partial_path, f: f

常见模式

模式 1:依赖下拉菜单

选择类型时,更新另一个字段中的可用选项:

  • 触发字段包含 data-action="turbo-fetch#perform"
  • 目标字段具有唯一 ID(例如 #substance-field)
  • Turbo stream 使用新的集合更新目标
模式 2:条件字段区域

根据选项显示或隐藏整个表单区域:

  • 使用 turbo_stream.replace 替换整个区域
  • 根据所选值渲染不同的局部模板
模式 3:成员路由与集合路由

大多数 turbo_fetch 路由都位于 :collection,但对于带有 ID 的嵌套资源:

resources :custom_parts, concerns: %i[turbo_fetch] do
  patch :turbo_fetch, on: :member # For child items with IDs
end

提示

  1. 目标 ID:确保目标元素具有唯一且稳定的 ID
  2. 表单上下文:turbo stream 视图会在 simple_form_for 中包装表单构建器,以保留表单上下文
  3. 授权:应用与 create/update 操作相同的授权规则
  4. 不要保存:turbo_fetch 操作会创建实例,但绝不保存
  5. 多次更新:一次响应中可以包含多个 turbo_stream 更新

故障排查

更新未显示:

  • 检查目标元素 ID 是否与 turbo_stream 选择器匹配
  • 确认 Stimulus 动作是否触发(检查浏览器控制台)
  • 确保 turbo_fetch 路由存在(运行 rails routes | grep turbo_fetch)

字段中的数据错误:

  • 确认 params 已在 material_params(或等效项)中获准
  • 检查模型的计算属性是否返回正确值

授权错误:

  • 确保 turbo_fetch 操作执行的授权检查与 new/create 相同

评论

支持 Markdown