如果你还没有,你可能想看看这个:https://edgeguides.rubyonrails.org/active_storage_overview.html#example
这是一个带有导入映射的默认 Rails 7 设置的启动器。主要取自上面的示例链接并包含在 Stimulus 中。
# config/importmap.rb
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "@rails/activestorage", to: "https://ga.jspm.io/npm:@rails/activestorage@7.0.2/app/assets/javascripts/activestorage.esm.js"
<!-- inside your form -->
<div data-controller="upload">
<%= form.file_field :avatar, direct_upload: true,
data: { upload_target: "input",
action: "change->upload#uploadFile" } %>
<div data-upload-target="progress"></div>
</div>
一旦选择文件,这将开始上传。和涡轮它是非阻塞的。只要浏览器不刷新,它就会上传。
// app/javascripts/controllers/upload_controller.js
import { Controller } from "@hotwired/stimulus";
import { DirectUpload } from "@rails/activestorage";
export default class extends Controller {
static targets = ["input", "progress"];
uploadFile() {
Array.from(this.inputTarget.files).forEach((file) => {
const upload = new DirectUpload(
file,
this.inputTarget.dataset.directUploadUrl,
this // callback directUploadWillStoreFileWithXHR(request)
);
upload.create((error, blob) => {
if (error) {
console.log(error);
} else {
this.createHiddenBlobInput(blob);
// if you're not submitting the form after upload, you need to attach
// uploaded blob to some model here and skip hidden input.
}
});
});
}
// add blob id to be submitted with the form
createHiddenBlobInput(blob) {
const hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("value", blob.signed_id);
hiddenField.name = this.inputTarget.name;
this.element.appendChild(hiddenField);
}
directUploadWillStoreFileWithXHR(request) {
request.upload.addEventListener("progress", (event) => {
this.progressUpdate(event);
});
}
progressUpdate(event) {
const progress = (event.loaded / event.total) * 100;
this.progressTarget.innerHTML = progress;
// if you navigate away from the form, progress can still be displayed
// with something like this:
// document.querySelector("#global-progress").innerHTML = progress;
}
}