Rails ActiveStorage: обратные вызовы DirectUpload - PullRequest
0 голосов
/ 27 мая 2018

У меня возникли проблемы с работой напрямую с объектом ActiveStorage DirectUpload.Я следую за примерами прямо из RailsGuides, но я должен что-то упустить.Вот краткий план моей проблемы:

  1. Что я пытаюсь сделать.
  2. Что я уже пытался сделать.
  3. Каковы мои текущие проблемы.

1.Что я пытаюсь выполнить

Используя ActiveStroage, я пытаюсь разрешить пользователю выбирать несколько файлов в простой форме и автоматически инициировать прямую загрузку после выбора файлов.

Это форма взаимодействия с конечным пользователем:

_media_upload_form.html.erb

<%= form_with url: elements_upload_path, local: true, id: "upload-elements" do %>
  <span class="btn btn-primary btn-file">
    <%= form.file_field :images, multiple: true, direct_upload: true %>
    Select File(s)
  </span>
<% end %>

2.То, что я уже пытался сделать

Чтобы выполнить автоматическую загрузку файлов после того, как пользователь выбрал файлы, мне нужно напрямую взаимодействовать с объектом DirectUpload.Эта подсказка находится прямо на ActiveStroage RailsGuides .У меня не было проблем с настройкой этого кода для работы со следующим кодом JS:

direct_uploads.js

import { DirectUpload } from "activestorage"

const input = document.querySelector('input[type=file]')

const onDrop = (event) => {
  event.preventDefault()
  const files = event.dataTransfer.files;
  Array.from(files).forEach(file => uploadFile(file))
}

input.addEventListener('change', (event) => {
  Array.from(input.files).forEach(file => uploadFile(file))
  input.value = null
})

const uploadFile = (file) {
  const url = input.dataset.directUploadUrl
  const upload = new DirectUpload(file, url)

  upload.create((error, blob) => {
    if (error) {
      // Handle the error
    } else {
      const hiddenField = document.createElement('input')
      hiddenField.setAttribute("type", "hidden");
      hiddenField.setAttribute("value", blob.signed_id);
      hiddenField.name = input.name
      document.querySelector('form').appendChild(hiddenField)
    }
  })
}

Итак, я выполнил одну цель.У меня были файлы загрузки, как только они были выбраны.Теперь моей следующей целью был доступ к событиям, чтобы я знал, когда загрузка завершена, прогресс и т. Д. Особенно важно знать, когда загрузка завершена, чтобы я мог отправить форму и создать объекты и прикрепить их к загруженным файлам.Итак, используя что-то вроде этого:

addEventListener("direct-upload:progress", event => {
  // ...
})

не будет работать, так как я обращаюсь к объекту DirectUpload напрямую.По крайней мере, это был мой опыт до сих пор.Немного озадаченный тем, почему, я заметил деталь (которую я изначально упустил) в ActiveStroage RailsGuides , в которой говорится, что вы можете связывать обработчики, создавая свой собственный класс загрузки DirectUpload.Итак, используя пример, приведенный в руководстве, я создал следующее:

my_uploader.js

import { DirectUpload } from "activestorage"

class MyUploader {
  constructor(file, url) {
    this.upload = new DirectUpload(this.file, this.url, this)
  }

  upload(file) {
    this.upload.create((error, blob) => {
      if (error) {
        // Handle the error
      } else {
        const hiddenField = document.createElement('input')
        hiddenField.setAttribute("type", "hidden");
        hiddenField.setAttribute("value", blob.signed_id);
        hiddenField.name = input.name
        document.querySelector('form').appendChild(hiddenField)
      }
    })
  }

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

  directUploadDidProgress(event) {
    console.log("Upload has some progress ....")
  }
}

// ... all ES6 export calls ...

direct_uploads.js

import { DirectUpload } from "activestorage"
import { MyUploader } from "my_uploader"

const input = document.querySelector('input[type=file]')

const onDrop = (event) => {
  event.preventDefault()
  const files = event.dataTransfer.files;
  Array.from(files).forEach(file => uploadFile(file))
}

input.addEventListener('change', (event) => {
  Array.from(input.files).forEach(file => uploadFile(file))
  input.value = null
})

const uploadFile = (file) {
  const url = input.dataset.directUploadUrl
  const upload = new MyUploader(file, url)
}

3.Мои текущие проблемы

Я думаю, что моя проблема в том, что я что-то упустил, возможно, шаг.Вызывается конструктор MyUploader, однако файлы больше не загружаются.Только конструктор вызывается и это все.Сам процесс загрузки больше не вызывается.Я заблудился о том, как заставить пользовательский MyUploader продолжать процесс загрузки, как это делает объект DirectUpload.

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

Спасибо!

Ответы [ 2 ]

0 голосов
/ 31 июля 2018

Я думаю, что проблема с вашим исходным кодом в том, что this.upload из конструктора имеет то же имя, что и ваша upload функция.

Глядя на исходный код Rails, они используют почти тот же код, что и выиспользовать в вашем MyUploader классе в direct_upload_controller.js, но они вызывают этот метод start.

0 голосов
/ 27 мая 2018

Покинув проект на некоторое время и вернувшись свежим взглядом, я увидел ответ.

DirectUpload может принимать три параметра, третий - объект MyUploader.

Итак, ответ примерно такой:

const my_uploader = new MyUploader(file, url)
const upload = new DirectUpload(file, url, my_uploader)
...