Rails 7.0.4+Stimulus.js:如何通过复选框更新模型?
Rails 7.0.4 + Stimulus.js 复选框更新模型问题排查
问题描述
使用Rails 7.0.4开发待办事项列表应用,尝试通过Stimulus.js实现复选框更新Task模型的completed字段功能,编写了以下代码但出现错误:
视图代码(index.html.erb)
<tbody> <% @tasks.each do |task| %> <tr data-controller="task" data-task-update-url="<%= task_path(task) %>"> <td><%= task.task_title%></td> <td><%= task.task_date%></td> <td> <input type = "checkbox" data-action = "task#toggle" data-target = "task.completed" <% if task.completed %> checked <% end %>> </td> <td> <%= link_to edit_task_path(task) do %> <i class="fa fa-edit"></i> <% end %> </td> <td> <%= link_to task_path(task), data: { "turbo_method": :delete, turbo_confirm: "Are you sure?" } do %> <i class="fa fa-trash"></i> <% end %> </td> </tr> <% end %> </tbody>
Stimulus控制器代码(task_controller.js)
import { Controller } from "stimulus" export default class extends Controller { static targets = [ "completed" ] toggle (event) { let formData = new FormData() formData.append("task[completed]", this.completedTarget.checked); fetch (this.data.get("update-url"), { body: formData, method: 'PATCH', credentials: "include", dataType: "script", headers: { "X-CSRF-Token": getMetaValue("csrf-token") }, }).then(function(response) { if (response.status != 204) { event.target.checked = !event.target.checked } }) } }
错误排查与修正
以下是代码中的核心问题及修复方案:
1. getMetaValue函数未定义
Stimulus控制器中直接调用的getMetaValue并非全局内置函数,需替换为原生DOM查询获取CSRF Token。
2. 无效的dataType参数
原生fetch API不支持dataType配置项(这是jQuery.ajax的专属参数),需移除该字段。
3. 响应处理逻辑不严谨
仅判断状态码204不够全面,需覆盖网络请求失败、服务器返回错误状态码等场景;同时恢复复选框状态的逻辑应依赖初始值,避免event.target上下文异常导致的问题。
4. 后端控制器需返回规范响应
确保TasksController的update动作返回符合REST规范的状态码。
修正后的Stimulus控制器(task_controller.js)
import { Controller } from "stimulus" export default class extends Controller { static targets = ["completed"] toggle(event) { const completedState = this.completedTarget.checked; const formData = new FormData(); formData.append("task[completed]", completedState); fetch(this.data.get("update-url"), { body: formData, method: "PATCH", credentials: "include", headers: { "X-CSRF-Token": document.querySelector('meta[name="csrf-token"]').content } }) .then(response => { if (!response.ok) { // 更新失败,恢复复选框原始状态 this.completedTarget.checked = !completedState; throw new Error(`请求失败,状态码:${response.status}`); } // 可选:添加成功后的UI反馈,标记已完成任务 this.element.classList.toggle("completed", completedState); }) .catch(error => { console.error("更新任务状态失败:", error); }); } }
修正后的后端控制器(tasks_controller.rb)
class TasksController < ApplicationController # ... 其他动作 ... def update @task = Task.find(params[:id]) if @task.update(task_params) head :no_content # 成功时返回204无内容状态码 else head :unprocessable_entity # 验证失败时返回422状态码 end end private def task_params params.require(:task).permit(:completed) end end
额外优化:添加已完成任务样式
在CSS中添加样式,让已完成任务更直观:
tr.completed td:first-child { text-decoration: line-through; color: #969696; }
内容的提问来源于stack exchange,提问作者igorfz
相关产品推荐
相关产品推荐

