使用 Rails Active Storage 和 Stimulus 对图像或附件进行排序

问题描述

我试图在我的 rails 表单中创建一个可排序的画廊部分。我已经设置了一些基础知识,例如向 active_storage_attachments 数据库添加位置列、主动存储本身、stimulus、stimulus-sortable 或 sortable.js、视图以及所有要上传和排序的内容,但我无法弄清楚 javascript 端或控制器操作正确地做到这一点。我曾尝试将其其他一些版本一起破解,但无济于事。我曾尝试遵循 GoRails Sortable Stimulus 指南,但我无法弄清楚如何将其路由到附件,而不是我所在项目的实际模型,例如项目。我不需要对项目进行排序,而是对项目中的图像进行排序。我现在得到的错误

NoMethodError (undefined method `each_with_index' for nil:NilClass):

我担心我没有获取其他人会获得的正确参数,因为我试图连接到附件 ID 而不是我目前正在使用的项目 ID。

所以我使用 Rails 6、Ruby 3、Stimulus JS、Stimulus Sortable、Postgres、Active Storage 和 Webpacker。

对于我的控制器,我添加一个 GoRails 论坛帖子:

def sort_attachments
   
    params[:attachments].each_with_index do |id,index|
      ActiveStorage::Attachment.where(id: id).update_all(position: index + 1)
    end
  
    head :ok
  end

我在 before_action 中允许 :sort_attachments

resources :projects,only: [:sort_attachments] do
    member do
      patch 'projects/sort/:id',action: :sort_attachments,as: 'sort_attachments'
    end
end

和我的表单视图:

 <% 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 %>" class="flex flex-wrap -mx-4 -mb-8">
          <% @project.images.order(:position).each do |images| %>
              <div data-id="<%= dom_id(attachment) %>" class="px-4 mb-8" >
                <%= image_tag images.variant(resize_to_limit: [150,150]).processed,class: "rounded shadow-md"%>
              </div>
          <% end %>  
        </div>
     </section>
<% end %>
<% end %>

这是从该论坛帖子和 Stackoverflow 上使用 Jquery 的另一篇帖子混合而成的。我更愿意坚持使用 Stimulus。

我的可排序控制器是:

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) {
    let id = event.item.dataset.id
    let data = new FormData()
    data.append("position",event.newIndex + 1)

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

任何帮助将不胜感激!提前致谢

解决方法

您没有发送附件,而是只发送了 :positions 参数,因此您会收到空异常错误。如果您想以这种特定方式解决它,您需要使用 Ajax 调用发送附件参数。但是,从上面的代码中并不清楚 :attachments 参数应该包含什么。

运行代码并将此行添加到控制器方法的顶部以进行调试。当您现在发送 ajax 请求时,它应该为您提供参数 raise params.inspect

中包含的数据

您已经以一种让自己变得困难的方式解决了这个问题。如果可能,您不应该接触附件数据库。我不知道为什么每次用户登录时您都希望画廊都相同,但是您可以通过在 index 方法中将图像设置为自己的变量来轻松解决这个问题,例如 @images 作为二维数组,然后将图像作为二维数组发送,并将响应作为与控制器排序方法中的 JS 相同的变量返回,如下所示:

@images = param[:images].map do |attachment,position|
            [[attachment,position]]
           end

如果您希望每次用户登录时排序都相同,那么一些缓存就足够了。