我有一个使用s3的活动存储示例的工作版本:
https://edgeguides.rubyonrails.org/active_storage_overview.html
现在,我希望能够执行的不是上完表格,而是在用户选择要上载的文件后立即执行上载。 实际上,就我而言,我有一个所见即所得的编辑器,该编辑器具有一个触发的 on drop 事件
var myCodeMirror = CodeMirror.fromTextArea(post_body, {
lineNumbers: true,
dragDrop: true
});
myCodeMirror.on('drop', function(data, e) {
var file;
var files;
// Check if files were dropped
files = e.dataTransfer.files;
if (files.length > 0) {
e.preventDefault();
e.stopPropagation();
file = files[0];
console.log('File: ' + file.name);
console.log('File: ' + file.type);
return false;
}
});
那么,由于文件删除触发了此事件,我是否可以将其以某种方式发送到活动存储,以便立即将文件上传到S3?
答案 0 :(得分:2)
Active Storage公开了DirectUpload
JavaScript类,您可以使用它来直接从客户端触发文件上传。
您可以利用它与第三方插件(例如Uppy,Dropzone)或您自己的自定义JS代码集成。
DirectUpload
您需要做的第一件事是确保将AWS S3设置为可以处理直接上传。这需要确保正确设置了CORS配置。
接下来,您只需实例化DirectUpload
类的实例,并向其传递要上传的文件和上传URL。
import { DirectUpload } from "activestorage"
// your form needs the file_field direct_upload: true, which
// provides data-direct-upload-url
const input = document.querySelector('input[type=file]')
const url = input.dataset.directUploadUrl
const upload = new DirectUpload(file, url)
upload.create((error, blob) => {
// handle errors OR persist to the model using 'blob.signed_id'
})
DirectUpload#create
方法将启动到S3的上传,并返回错误或上传的文件Blob。
假设没有错误,最后一步是将上传的文件持久保存到模型中。您可以使用blob.signed_id
并将其放在页面上某个地方的隐藏字段中,也可以使用AJAX请求来更新模型。
在上述情况下,要开始直接在drop上进行上传,只需将上面的代码放入drop
处理程序中。
类似这样的东西:
myCodeMirror.on('drop', function(data, e) {
// Get the file
var file = e.dataTransfer.files[0];
// You need a file input somewhere on the page...
const input = document.querySelector('input[type=file]')
const url = input.dataset.directUploadUrl
// Instantiate the DirectUploader object
const upload = new DirectUpload(file, url)
// Upload the file
upload.create((error, blob) => { ... })
});
如果您仅使用资产管道而不使用JavaScript捆绑工具,则可以像这样创建DirectUpload
类的实例
const upload = new ActiveStorage.DirectUpload(file, url)
答案 1 :(得分:0)
该主题的主要问题是-您不能在表单的Java脚本部分中导入DataUpload。但是我们可以创建对象InstantUploader,如下所示:
全局Java脚本部分
upload / uploader.js
import { DirectUpload } from "@rails/activestorage"
export default class Uploader {
constructor(file, url) {
this.file = file
this.url = url
this.directUpload = new DirectUpload(this.file, this.url, this)
}
upload() {
return new Promise((resolve, reject) => {
this.directUpload.create((error, blob) => {
if (error) {
// Handle the error
reject(error)
} else {
// Add an appropriately-named hidden input to the form
// with a value of blob.signed_id
resolve(blob)
}
})
})
}
}
upload / index.js
import Uploader from './uploader.js'
export default {
upload (file, url) {
const uploader = new Uploader(file, url)
return uploader.upload()
}
}
application.js
window.ImmediateUploader = require('./upload');
组成部分
现在,我们可以使用InstantUploader将所选文件直接上传到活动存储中,并在加载后不提交提交就更新映像:
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<div class="row">
<img id="avatar" class="centered-and-cropped" width="100" height="100" style="border-radius:50%" src="<%= url_for(user.photo) %>">
<button type="button" class="btn" onclick="event.preventDefault(); document.getElementById('user_photo').click()">Change avatar</button>
</div>
<%= f.file_field :photo, direct_upload: true, class: "hiddenfile" %>
</div>
<div class="form-actions">
<%= f.button :submit, t(".update"), class: 'btn btn-primary' %>
</div>
<% end %>
<% content_for :js do %>
<script>
const input = document.querySelector('input[type=file]')
input.addEventListener('change', (event) => {
Array.from(input.files).forEach(file => uploadFile(file))
// clear uploaded files from the input
input.value = null
})
const uploadFile = (file) => {
// your form needs the file_field direct_upload: true, which
// provides data-direct-upload-url
const url = input.dataset.directUploadUrl;
ImmediateUploader.default.upload (file, url)
.then(blob => {
// get blob.signed_id and add it to form values to submit form
const hiddenField = document.createElement('input')
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("value", blob.signed_id);
hiddenField.name = input.name
document.querySelector('form').appendChild(hiddenField)
// Update new avatar Immediately
document.getElementById('avatar').src = '/rails/active_storage/blobs/' + blob.signed_id + '/' + blob.filename;
// Update photo in Database
axios.post('/users/photo', { 'photo': blob.signed_id }).then(response => {});
});
}</script>
<% end %>
控制器:
class RegistrationController < Devise::RegistrationsController
def update
super
@user = current_user
@user.avatar = url_for(@user.photo.variant(resize_to_limit: [300, 300]).processed) if @user.photo.attached?
@user.save
end
def updatephoto
@photo = params[:photo]
@user = current_user
@user.photo = @photo
@user.save
@user = current_user
@user.avatar = url_for(@user.photo.variant(resize_to_limit: [300, 300]).processed) if @user.photo.attached?
@user.save
end
end