我在直接使用 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 对象一样。
任何人都可以提供的任何方向将不胜感激。
谢谢!