Rails+Stimulus环境下Tom-select创建记录后下拉选项不更新
在Rails应用中结合Stimulus使用tom-select,目标是动态创建Vendor模型记录后,能在Trx模型的下拉菜单中选择该记录。目前已成功通过fetch请求创建记录,但下拉菜单并未更新。参考SupeRails #17视频12:14处的内容,其网络标签页显示两个请求(一个fetch和一个xhr),但我的应用仅显示一个状态码为200的fetch请求。
请问如何操作才能让新创建的记录显示在下拉菜单中?
Stimulus控制器(vendor_select_controller.js)
settings = { plugins: ['clear_button'], selectOnTab: true, valueField: 'id', labelField: 'name', searchField: 'name', sortField: { field: "name", direction: "asc" }, create: function (input, callback) { const data = { name: input } const token = document.getElementsByName("csrf-token")[0].content; fetch('/vendors', { body: JSON.stringify(data), method: 'POST', dataType: 'script', credentials: 'include', headers: { "X-CSRF-Token": token, "Content-Type": "application/json", "Accept": "application/json" }, }).then((response) => { return response.json() }) .then((data) => { callback({ value: data.id, text: data.name }) }) }, onItemAdd: function () { this.setTextboxValue(''); this.refreshOptions(); }, }
VendorsController代码
class VendorsController < ApplicationController ... def create @vendor = Vendor.new(vendor_params) respond_to do |format| if @vendor.save format.html { redirect_to vendors_path } format.json { render json: @vendor } else format.html { render :new, status: :unprocessable_entity } format.json { render json: @vendor.errors, status: :unprocessable_entity } end end end
Trx表单中的Vendor collection_select字段
<%= f.collection_select :vendor_id, Vendor.all, :id, :name, {:prompt => "Select Vendor"}, {class: "w-full", data: { controller: "vendor-select" } } %>
控制台日志输出
Started POST "/vendors" for 127.0.0.1 at 2023-04-14 16:18:43 -0700 Processing by VendorsController#create as JSON Parameters: {"name"=>"Pines8", "vendor"=>{"name"=>"Pines8"}} TRANSACTION (0.1ms) begin transaction ↳ app/controllers/vendors_controller.rb:11:in `block in create' Vendor Create (0.3ms) INSERT INTO "vendors" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "Pines8"], ["created_at", "2023-04-14 23:18:43.634246"], ["updated_at", "2023-04-14 23:18:43.634246"]] ↳ app/controllers/vendors_controller.rb:11:in `block in create' TRANSACTION (6.2ms) commit transaction ↳ app/controllers/vendors_controller.rb:11:in `block in create' Completed 200 OK in 12ms (Views: 0.3ms | ActiveRecord: 6.6ms | Allocations: 2695)
核心问题是tom-select的create回调参数格式与配置不匹配,导致新记录无法被正确识别并添加到下拉列表,按以下步骤修改即可解决:
修正回调参数格式:
你设置了valueField: 'id'和labelField: 'name',但原代码传给callback的是{ value: data.id, text: data.name },这和tom-select的字段映射不对应。需要改成和配置字段一致的键名,同时手动刷新选项确保生效:create: function (input, callback) { const data = { name: input } const token = document.getElementsByName("csrf-token")[0].content; fetch('/vendors', { body: JSON.stringify(data), method: 'POST', credentials: 'include', headers: { "X-CSRF-Token": token, "Content-Type": "application/json", "Accept": "application/json" }, }) .then(response => response.json()) .then(data => { callback({ id: data.id, name: data.name }); this.refreshOptions(); }) .catch(error => console.error('创建供应商失败:', error)); }移除无效参数:
Fetch API不支持jQuery的dataType: 'script'参数,直接删掉即可。统一参数格式(可选但推荐):
日志显示请求参数同时包含顶级name和嵌套的vendor[name],可以修改前端请求数据格式,更符合Rails约定:const data = { vendor: { name: input } }同时确保控制器的强参数设置正确:
private def vendor_params params.require(:vendor).permit(:name) end
修改后,新创建的Vendor会被tom-select正确添加到下拉选项中,无需额外请求——视频中的两个请求是因为使用了Turbo Stream等其他方案,你的场景用tom-select原生回调即可解决问题。
内容的提问来源于stack exchange,提问作者chug

