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

Rails Active Storage配合Stimulus实现附件排序及NoMethodError问题求解

Rails可排序图库模块修复方案

报错原因

NoMethodError (undefined method 'each_with_index' for nil:NilClass) 是因为前端未向后端传递attachments参数,控制器中params[:attachments]为空值导致。同时代码存在变量名错误、路由定义冗余、参数传递逻辑不匹配问题,按以下步骤修改即可:


1. 路由配置修改

删除冗余的路径前缀,修正member路由定义:

resources :projects do
  member do
    patch :sort_attachments, as: 'sort_attachments'
  end
end

修改后生成的路由为/projects/:id/sort_attachments,直接关联当前操作的项目,权限控制更安全。


2. 视图代码修改

修正循环变量名、未定义变量问题,传入项目参数生成正确的接口地址:

<% if @project.persisted? %>
<% if @project.images.attached? %>
    <section class="pb-6  px-0">
        <div data-controller="sortable" data-sortable-animation-value="150" data-sortable-url="<%= sort_attachments_project_path(@project) %>" class="flex flex-wrap -mx-4 -mb-8">
          <% @project.images.order(:position).each do |attachment| %>
              <div data-id="<%= attachment.id %>" class="px-4 mb-8" >
                <%= image_tag attachment.variant(resize_to_limit: [150, 150]).processed, class: "rounded shadow-md"%>
              </div>
          <% end %>  
        </div>
     </section>
<% end %>
<% end %>

修改点:

  • 循环变量从images改为attachment,修复之前调用dom_id(attachment)时变量未定义的问题
  • data-id直接使用附件的纯ID,无需dom_id包装
  • 调用路由辅助方法时传入@project参数,生成正确的接口地址

3. Stimulus控制器修改

调整参数传递逻辑,拖动结束后传递所有排序后的附件ID数组到后端:

import { Controller } from "stimulus"
import Sortable from "sortablejs"

export default class extends Controller {
  connect() {
    this.sortable = Sortable.create(this.element, {
      group: 'shared',
      animation: 150,
      onEnd: this.end.bind(this)
    })
  }

  end(event) {
    // 获取排序后的所有附件ID数组
    const attachmentIds = Array.from(this.element.querySelectorAll('[data-id]')).map(el => el.dataset.id)
    const data = new FormData()
    data.append("attachments[]", ...attachmentIds)

    Rails.ajax({
      url: this.data.get("url"),
      type: 'PATCH',
      data: data
    })
  }
}

修改点:

  • 不再需要替换URL中的ID参数,直接使用视图传入的完整接口地址
  • 按排序顺序收集所有附件ID,组装为attachments数组传递到后端,匹配控制器的遍历逻辑

4. 控制器逻辑修改

增加项目关联校验,避免越权修改其他项目的附件:

def sort_attachments
  @project = Project.find(params[:id])
  params[:attachments].each_with_index do |id, index|
    @project.images.where(id: id).update_all(position: index + 1)
  end
  head :ok
end

修改点:

  • 先查找当前项目,仅更新当前项目下的图片附件,避免恶意操作其他项目资源
  • 逻辑和参数传递匹配,确保params[:attachments]有值时才会执行遍历更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 05:36:05