RoR:使用 Dropzone.js 和 jQuery 可排序

RoR: using Dropzone.js with jQuery sortable

我在我的 rails 应用程序中结合了 Dropzone Js 和回形针,我还设法将 jquery 的排序应用到它。

我的 objective 是:

  1. 能够将每张图片的位置保存到数据库中 上传成功
  2. 当我更改(排序)图像的顺序时更新数据库中每个图像的位置。

我的上传模型有 :image 和 :position 我的路线有集合 {post "sort"}

我的控制器代码:

class UploadsController < ApplicationController

  def new
    @upload = Upload.new
  end

  def upload_list
    @uploads = Upload.all.select(:id, :image_file_name, :image_file_size).order("position")

    respond_to do |format|
      format.json {render json: @uploads.to_json(methods: [:path])}
    end
  end

  def create
    @upload = Upload.create(upload_params)
    @upload.position = params[:upload][:position]

    if @upload.save
      render json: { message: "success", fileID: @upload.id }, :status => 200
    else
      render json: { error: @upload.errors.full_messages.join(',')}, :status => 400
    end
  end

  def sort
    //params[:upload] gives undefined method for nil error 
    Upload.all.each_with_index do |id, index|
      Upload.where(id: id).update_all({position: index+1})
    end
    render nothing: true
  end

  def destroy
    @upload = Upload.find(params[:id])
    if @upload.destroy
      render json: { message: "File deleted from server" }
    else
      render json: { message: @upload.errors.full_messages.join(',') }
    end
  end

  private
    def upload_params
      params.require(:upload).permit(:image, :position)
    end
end  

upload.rb:

class Upload < ActiveRecord::Base

  has_attached_file :image, :styles => { :medium => "300x300>",:thumb => "100x100>" }

  validates_attachment :image,
                   :presence => true,
                   :content_type => { :content_type => /\Aimage\/.*\Z/ },
                   :size => { :less_than => 1.megabyte } 

  def path
    image.url
  end

  def as_json(options = { })
    h = super(options)
    h["name"] = h.delete "image_file_name"
    h["size"] = h.delete "image_file_size"
    h
  end

end 

new.html.erb:

<h1>Uploads#new</h1>

<%= form_for(@upload, html: { multipart: true, class: "dropzone"}) do |f| %>
  <div class="fallback">
    <%= f.file_field :image %>
    <%= f.submit "Upload" %>
  </div>
<% end %>  

最后 uploads.js:

$(document).ready(function(){

  Dropzone.autoDiscover = false;

  $("#new_upload").dropzone({
    maxFilesize: 1,
    paramName: "upload[image]",
    addRemoveLinks: true,
    dictRemoveFile: "Delete",

    //to show existing images from db 
    init: function() {
      var thisDropZone = this;
      $.getJSON('upload_list', function(data) {
        $.each(data, function(index, val) {
          var mockFile = { name: val.name, size: val.size };
          thisDropZone.emit("addedfile", mockFile);
          thisDropZone.emit("thumbnail", mockFile, val.path);
          $(mockFile.previewTemplate).find('.dz-remove').attr('id', val.id);

          // adding id attribute for serialize
          $(".dz-preview:last-child").attr('id', "image_" + val.id);
        });
      });
    },

    success: function(file, response){
      $(file.previewTemplate).find('.dz-remove').attr('id', response.fileID);
      $(file.previewElement).addClass("dz-success");

      var order = $('.dropzone').sortable('serialize');
      $.ajax({
        type: 'POST',
        url: '/uploads/sort',
        data: order,
        success: function(data){
          console.log(data);
        }        
      });
    },

    removedfile: function(file){
      var id = $(file.previewTemplate).find('.dz-remove').attr('id');
      file.previewElement.remove();

      $.ajax({
        type: 'DELETE',
        url: '/uploads/' + id,
        success: function(data){
          console.log(data.message);
        }
      });

      var order = $('.dropzone').sortable('serialize');
      $.ajax({
        type: 'POST',
        url: '/uploads/sort',
        data: order,
        success: function(data){
          console.log(data);
        }        
      });
    }
  });

 //this function is for sorting + updating positions of old images loaded by the init function.
  $(function() {
    $(".dropzone").sortable({
      items:'.dz-preview',
      cursor: 'move',
      opacity: 0.5,
      containment: '.dropzone',
      distance: 20,
      update: function(event, ui) {
        var order = $('.dropzone').sortable('serialize');
        $.ajax({
          type: 'POST',
          url: '/uploads/sort',
          data: order,
          success: function(data){
            console.log(data);
          }        
        });
      }
    });
    $(".dropzone").disableSelection();
  });
}); 

我知道我有很多清理工作要做,但我想先让它开始工作。

我知道我需要在 dropzone 的每个图像的 .dz-preview 中有一个以“_”开头的 id 才能进行序列化。然而,成功函数中的 ajax post 在不应用任何 id 属性的情况下工作正常,所以当我上传 3 张图像时,在数据库中位置分别为 1、2 和 3,removedfile 函数也有效,如果我删除第二张图片,由于控制器中的排序方法,image1 获得位置“1”并且 image3 获得位置属性更新为 2。

我尝试在 init 函数中添加一行以将 id 属性附加到 .dz-preview 并刷新页面,以便我测试 init 函数并再次尝试排序,但它是一样的,我得到的是:

Started POST "/uploads/sort" for 127.0.0.1 at 2015-01-12 12:47:39 +0200
Processing by UploadsController#sort as */*
Parameters: {"image"=>["318", "320", "319"]}
Upload Load (2.7ms)  SELECT "uploads".* FROM "uploads"
SQL (5.4ms)  UPDATE "uploads" SET "position" = 1 WHERE "uploads"."id" = 318
SQL (14.7ms)  UPDATE "uploads" SET "position" = 2 WHERE "uploads"."id" = 319
SQL (1.8ms)  UPDATE "uploads" SET "position" = 3 WHERE "uploads"."id" = 320
Rendered text template (0.1ms)
Completed 200 OK in 54ms (Views: 2.0ms | ActiveRecord: 29.6ms)

注意参数的顺序,因此图像“318”应该占据位置 1,“320”应该占据位置 2,“319”应该占据位置 3...但是如图所示,更新忽略了新顺序...

知道我遗漏了什么吗?是sort方法还是.sortable函数?

谢谢

使用以下代码更新您的排序操作。

  def sort
    images = Upload.where(id: params[:image])
    images.each do |image|
      if position = params[:image].index(image.id.to_s)
        image.update_attribute(:position, position + 1) unless image.position == position
      end 
    end 
    render nothing: true
  end