Rails 7 从浏览器客户端查看并直接上传图片
Rails 7 view and direct upload image from browser client
我已经很久没有使用 Rails 作为 Web 应用程序的前端了,我当然想使用最新版本,但似乎已经发生了很多变化,我不知道不知道哪个是最 Rails 的方法了。
我试过使用 JQuery 和 FileUpload 插件,但我们没有 JQuery 了,我的意思是我试过添加它,但在屁股使用新的导入映射(我有问题,我知道如果我查找一些教程我可以做到),但这似乎与 rails 应用程序中 JS 当前的心态背道而驰。
然后我去检查新的 Hotwire + Stimulus,但我什至不知道从哪里开始,但从我看到的一点点不知道是否会处理这种情况:我的 S3 Bucket
已经有一个 presigned_url
,并且只有一个带有 f.file_field
的表单,我想将此文件从客户端浏览器直接上传到 S3
做 POST
请求,这样用户就不会在等待上传完成时被阻塞
如果我错了请纠正我但是要触发 JS 函数 Rails 现在的方法是使用 Stimulus
和 HTML Data Attributes
但我不确定我是否可以通过此数据属性中的文件。
查看其他教程,我开始认为最好的方法是使用 turbo_stream_tag
来包装我的表单,然后在提交表单时将点击此涡轮控制器,它将充当 ajax 请求,运行 使用 Net:HTTP
甚至 s3
gem 本身异步执行 post 请求,我只是不确定我是否会有权访问该文件。
有好心人来澄清一下吗?感谢和抱歉漫长的 post.
如果你还没有,你可能想看看这个:https://edgeguides.rubyonrails.org/active_storage_overview.html#example
这是一个带有默认 Rails 7 导入映射设置的启动器。主要取自上面的示例 link 并包含在 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>
这将在选择文件后立即开始上传。使用 Turbo,它是非阻塞的。只要浏览器不刷新就会上传。
// 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 a 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;
}
}
我已经很久没有使用 Rails 作为 Web 应用程序的前端了,我当然想使用最新版本,但似乎已经发生了很多变化,我不知道不知道哪个是最 Rails 的方法了。
我试过使用 JQuery 和 FileUpload 插件,但我们没有 JQuery 了,我的意思是我试过添加它,但在屁股使用新的导入映射(我有问题,我知道如果我查找一些教程我可以做到),但这似乎与 rails 应用程序中 JS 当前的心态背道而驰。
然后我去检查新的 Hotwire + Stimulus,但我什至不知道从哪里开始,但从我看到的一点点不知道是否会处理这种情况:我的 S3 Bucket
已经有一个 presigned_url
,并且只有一个带有 f.file_field
的表单,我想将此文件从客户端浏览器直接上传到 S3
做 POST
请求,这样用户就不会在等待上传完成时被阻塞
如果我错了请纠正我但是要触发 JS 函数 Rails 现在的方法是使用 Stimulus
和 HTML Data Attributes
但我不确定我是否可以通过此数据属性中的文件。
查看其他教程,我开始认为最好的方法是使用 turbo_stream_tag
来包装我的表单,然后在提交表单时将点击此涡轮控制器,它将充当 ajax 请求,运行 使用 Net:HTTP
甚至 s3
gem 本身异步执行 post 请求,我只是不确定我是否会有权访问该文件。
有好心人来澄清一下吗?感谢和抱歉漫长的 post.
如果你还没有,你可能想看看这个:https://edgeguides.rubyonrails.org/active_storage_overview.html#example
这是一个带有默认 Rails 7 导入映射设置的启动器。主要取自上面的示例 link 并包含在 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>
这将在选择文件后立即开始上传。使用 Turbo,它是非阻塞的。只要浏览器不刷新就会上传。
// 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 a 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;
}
}