如何在dropzone rails中使用activestorage的直接上传

时间:2019-02-11 05:33:08

标签: ruby-on-rails rails-activestorage dropzone

Dropzone直接上传到nginx,我不想增加文件大小限制。活动存储确实具有直接上传功能,可以直接从客户端上传文件。但是我很困惑如何将其与dropzone一起使用,因为dropzone似乎以自己的方式上传文件,而direct_upload:true在这种情况下不起作用。

我的表单:

<%= form_for(@submission, html: { multipart: true, class: "dropzone", id: "file-upload"}) do |f| %>
     <%= f.hidden_field :user_id %>
     <%= f.hidden_field :problem_id %>
<% end %>

1 个答案:

答案 0 :(得分:0)

我不确定您的设置是什么,但这是使用dropzone进行活动存储所需要的。

1)application.js //= require dropzone

2)application.scss

 *= require dropzone

// ...

.dropzone-target {
  height: 100px;
  width: 100px;
  background-color: lightgrey;
}

3)dropzone_controller.js

// app/javascript/controllers/dropzone_controller.js

import {Controller} from "stimulus";
import {DirectUpload} from "activestorage";

export default class extends Controller {

  uploadFile = (file, url, name) => {
    const upload = new DirectUpload(file, url, this);

    upload.create((error, blob) => {
      if (error) {
        // Handle the error
      } else {
        // Add an appropriately-named hidden input to the form with a
        //  value of blob.signed_id so that the blob ids will be
        //  transmitted in the normal upload flow
        const hiddenField = document.createElement('input');
        hiddenField.setAttribute("type", "hidden");
        hiddenField.setAttribute("value", blob.signed_id);
        hiddenField.name = name;
        this.element.querySelector('form').appendChild(hiddenField);
      }
    });
  };

  connect() {
    const root = this.element;
    const fileInputField = root.querySelector('input[type="file"]');
    const url = fileInputField.dataset.directUploadUrl;
    const name = fileInputField.name;

    fileInputField.remove();

    this.myDropzone = new Dropzone(root.querySelector('.dropzone-target'), {
      url,
      autoQueue: false,
      previewTemplate: '<div class="list-group-item w-100">\n' +
        '  <div class="row">' +
        '    <div class="col-2"><img data-dz-thumbnail class="img img-fluid" /></div>\n' +
        '    <div class="col-4">\n' +
        '        <span data-dz-size />\n' +
        '    </div><div class="col-6">\n' +
        '        <span data-dz-name></span>\n' +
        '    </div>\n' +
        '  </div><div class="row">\n' +
        '    <div class="col-12 mt-2"><div class="progress"><div class="progress-bar bg-dark" style="width:0%;" ></div></div></div>' +
        '  </div>\n' +
        '</div>',
      drop: (event) => {
        event.preventDefault();
        const files = event.dataTransfer.files;
        Array.from(files).forEach(file => this.uploadFile(file, url, name))
      }
    });
  }

  disconnect() {
    this.myDropzone = null;
  }

  directUploadWillStoreFileWithXHR(request) {
    request.upload.addEventListener("progress",
      event => this.directUploadDidProgress(event));
  }

  directUploadDidProgress(event) {
    const root = this.element;
    root.querySelector('.progress .progress-bar').style.width = `${event.loaded * 100 / event.total}%`;
  }

}

4)edit.html.slim

div[data-controller="dropzone"]
  = form_for @some_model do |f|
    = f.file_field :file, direct_upload: true
    .dropzone-target Drop files here

5)Gemfile

source 'https://rails-assets.org' do
  gem 'rails-assets-dropzone'
end

6)package.json

{
  "dependencies": {
    "@rails/webpacker": "3.4",
    "activestorage": "^5.2.1",
    "stimulus": "^1.0.1",
},
  "devDependencies": {
    "webpack-dev-server": "2.11.2"
  }
}