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
相关产品推荐
相关产品推荐

