问题描述
我试图在我的 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。
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
如果您希望每次用户登录时排序都相同,那么一些缓存就足够了。