Rails ActiveStorage:DirectUpload 回调

Posted

技术标签:

【中文标题】Rails ActiveStorage:DirectUpload 回调【英文标题】:Rails ActiveStorage: DirectUpload callbacks 【发布时间】:2018-11-05 23:25:25 【问题描述】:

我在直接使用 ActiveStorage 的 DirectUpload 对象时遇到了一些问题。我正在遵循 RailsGuides 中的示例,但我一定遗漏了一些东西。这是我的问题的快速布局:

    我正在努力实现的目标。 我已经尝试过。 我目前的问题是什么。

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 对象一样。

任何人都可以提供任何方向将不胜感激。

谢谢!

【问题讨论】:

【参考方案1】:

离开我的项目一段时间后,我以崭新的眼光回来,我看到了答案。

DirectUpload 可以带三个参数,第三个是MyUploader 对象。

所以答案是这样的:

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

【讨论】:

第二行应该是const upload = new DirectUpload(file, url, my_uploader) 这很有帮助,因为从 Active Storage 指南一目了然【参考方案2】:

我认为您的初始代码的问题在于构造函数中的this.upload 与您的upload 函数具有相同的名称。

查看 Rails 源代码,它们使用的代码几乎与您在 direct_upload_controller.js 中的 MyUploader 类中使用的代码相同,但它们将该方法称为 start

【讨论】:

以上是关于Rails ActiveStorage:DirectUpload 回调的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ActiveStorage (Rails 5.2) 中更新附件

使用 ActiveStorage 将 Cloudinary 图像附加到 Rails 模型

从 Rails 6 中删除 ActiveStorage 路由

Rails ActiveStorage:DirectUpload 回调

上传前的 Rails 5.2 ActiveStorage 裁剪附件

如何在 Rails 5.2 中复制存储在 ActiveStorage 中的文件