使用活动存储对图像进行排序

Sorting Images using Active Storage

我正在尝试使用 Active Storage 来管理图像。我让多个上传工作正常,但我想使用 acts_as_list 位置和 jQuery 可排序来使用 ajax 管理他们的订单,就像在 the video on this site 中一样。在普通模型中,我会 运行 迁移以向模型添加位置。但看起来我无权访问 Blob 或 Attachement 模型。我将如何解决这个问题?还是我必须重新使用 Carrierwave?任何帮助将不胜感激。

为了澄清,让我添加代码。

show.html.erb

<p id="notice"><%= notice %></p>

<p>
  <strong>Title:</strong>
  <%= @post.title %>
</p>

<p>
  <strong>Content:</strong>
  <%= @post.content %>
</p>

<% if @post.images.attached? %>
<p>
  <strong>Images:</strong>
  <br>
  <div id="images" class="list-group" data-url="<%= sort_posts_path %>">
  <% @post.images.order(:position).each do |image| %>
    <%= link_to image_tag image.variant(resize: "200x200"), class: "list-group-item", id: dom_id(image) %>
  <% end %>
  </div>
</p>
<% end %>

<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>

posts.js

document.addEventListener("turbolinks:load", function() {

  $("#images").sortable({
    update: function(e, ui) {
      /* Update active storage database entry for each POST image. */
      /* This is the RAILS AJAX from the tutorial */
      Rails.ajax({
        url: $(this).data("url"),
        type: "PATCH",
        data: $(this).sortable('serialize'),
    }
  });

});

routes.rb

Rails.application.routes.draw do
  resources :posts do
    collection do
      patch :sort
    end
  end
end

posts_controller.rb

def sort
  params[:image].each_with_index do |id, index|
    Post.image.where(id: id).update_all(position: index + 1)
  end

  head :ok
end

更新更好的方法 鉴于 MyModel.images returns 一个 ActiveStorageAttachment 模型数组,我刚刚通过创建迁移以将位置列添加到 active_storage_attachments table 来完成测试 然后使用此字段对图像进行排序效果很好

rails g migration add_order_by_to_active_storage_attachments position:integer

显然不要忘记 运行 迁移,您可能希望在 运行 之前编辑迁移以更新现有记录上的职位字段。

现在您可以将位置字段设置为您想要的任何值,然后您可以使用 my_model.images.order(:position)

如果我扩展这个答案对你有帮助,请在评论中提问

为了更清楚起见,更新一下,需要对图像数组进行排序,对吗?为了实现这一点,在视图中重新组织图像后,当表单回发到控制器时,需要设置您刚刚在迁移中创建的位置字段。

因此,在相关的控制器操作、更新和创建中,您可以循环遍历 @post.images 设置每个图像的位置并将图像保存回数据库。这将确保当您使用 @post.images.order(:position) 查看图像时,它们会以正确的顺序显示。

这就是我最终为了让它在实际应用程序中工作而做的事情。 "simple" 功能中的所有内容令人惊叹。

Gemfile

gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'acts_as_list'

用于将 position 添加到 Active Storage 的迁移

class AddPositionToActiveStorageAttachments < ActiveRecord::Migration[5.2]
  def change
    add_column :active_storage_attachments, :position, :integer, default: 0
  end
end

sorting.js

这允许我们使用 sort-me class.

对任何内容进行排序
$(function() {

  $(".sort-me").sortable({
    update: function(e, ui){
      ui.placeholder.height(ui.item.height());
      Rails.ajax({
        url: $(this).data("url"),
        type: "PATCH",
        data: $(this).sortable('serialize')
      });
    }
  }).disableSelection();

});

edit.html.erb

这是页面上相关代码的片段。将 sort-me class 添加到包含的 div 将使可排序的元素脱离下一组项目。

<div id="product-attachments" class="sort-me" data-url="<%= sort_attachments_admin_products_path %>">
  <% @product.images.order(:position).each do |attachment| %>
    <div id="<%= dom_id(attachment) %>" class="ui-state-default image-box">
      <%= image_tag attachment.variant(combine_options: {auto_orient: true, thumbnail: '200x200^', gravity: 'center', extent: '200x200' }) %>
      <%= link_to "Delete", delete_image_admin_products_path(@product.id, attachment.id), method: :delete, class: "btn btn-xs", data: {confirm: "Are you sure?"} %>
    </div>
  <% end %>
</div>

routes.rb

这些是相关路线。在这种情况下,我们使用的是管理命名空间。因此,如果您在没有它的情况下使用它,请确保您的 routes/paths 不包括管理部分。

namespace 'admin' do
  resources :products do
    collection do
      patch '/products/sort/:id', action: :sort_attachments, as: 'sort_attachments'
      delete '/products/:id/images/:image_id', action: 'delete_image', as: 'delete_image'
    end
  end
end

products_controller.rb

排序删除路由的相应控制器操作。

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

  head :ok
end

def delete_image
  ActiveStorage::Attachment.where(id: params[:image_id])[0].purge
  redirect_to edit_admin_product_path(params[:id]), notice: 'Image was successfully deleted.'
end