简体   繁体   中英

Sorting Images or Attachments with Rails Active Storage and Stimulus

I attempting to make a sortable gallery section in my rails form. I have setup the basics like adding a position column to the active_storage_attachments database, active storage itself, stimulus, stimulus-sortable or sortable.js, views and all to upload and sort, but I cannot figure out the javascript side or the controller action to properly do this. I have tried hacking together some others versions of this to no avail. I have tried following GoRails Sortable Stimulus guide but I cant figure out how to route it to the attachments and not the actual model of the item I am in such as Projects. I don't need to sort projects but the images within projects. The error I am getting now is

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

I fear that I am not grabbing the right parameters that the others would get since I am trying to connect to the attachments id and not the project id I am currently working in.

So I am using Rails 6, Ruby 3, Stimulus JS, Stimulus Sortable, Postgres, Active Storage and Webpacker.

For my controller I have added this which was off of a GoRails forum post:

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

I allowed:sort_attachments in the before_action

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

and my form view:

 <% 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 %>

This was mashed up from that forum post and another post here on Stackoverflow which uses Jquery. I would prefer to stick with Stimulus.

My sortable controller is:

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

Any help would be greatly appreciated! Thank you in advance

You are not sending in the attachments, but only the param:positions, so you get a null exception error. If you want to solve it in this particular way you need to send the attachments param in with the Ajax call. However, it is not clear from the code above what the:attachments param should contain.

Run the code and add this line to the top of your controller method to debug. When you send a ajax request now it should give you the data contained in the params raise params.inspect

You've solved this problem in a way where you make it hard for your self. You should NOT touch the attachment databases if possible. I've no idea why you would want the gallery to be the same for each time the user log in, but you can easily solve this by setting the images as a own variable in the index method for example @images as a 2d array, then sending the images in as a 2d array and return the response as the same variable as JS in the controller sort method like so:

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

If you want the sorting to be the same each time the user logs in, some caching should be good enough.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM