Сортировка изображений или вложений с помощью 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):

Я боюсь, что я не получаю правильные параметры, которые получат другие, поскольку я пытаюсь подключиться к идентификатору вложения, а не к идентификатору проекта, над которым я сейчас работаю.

Итак, я использую 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

Я разрешил :sort_attachments в before_action

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
    })
  }
}

Любая помощь будет принята с благодарностью! заранее спасибо


person Brendan    schedule 09.05.2021    source источник


Ответы (1)


Вы не отправляете вложения, а только параметр :positions, поэтому вы получаете нулевую ошибку исключения. Если вы хотите решить это именно таким образом, вам нужно отправить параметр вложения с вызовом Ajax. Однако из приведенного выше кода неясно, что должен содержать параметр :attachments.

Запустите код и добавьте эту строку в начало метода контроллера для отладки. Когда вы отправляете запрос ajax сейчас, он должен предоставить вам данные, содержащиеся в параметрах raise params.inspect

Вы решили эту проблему таким образом, что усложнили ее себе. Вам НЕ следует трогать базы данных вложений, если это возможно. Я понятия не имею, почему вы хотите, чтобы галерея была одинаковой при каждом входе пользователя в систему, но вы можете легко решить эту проблему, установив изображения как собственную переменную в методе индекса, например @images как 2d-массив, затем отправка изображений в виде массива 2d и возврат ответа в виде той же переменной, что и JS, в методе сортировки контроллера, например:

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

Если вы хотите, чтобы сортировка была одинаковой каждый раз, когда пользователь входит в систему, некоторого кэширования должно быть достаточно.

person TTD    schedule 02.06.2021