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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 05:30:46