【问题标题】:How can I upload an image to S3 with rails' Active Storage from a <canvas /> in a rails form?如何从 <canvas /> 以 rails 形式将图像上传到带有 rails 的 Active Storage 的 S3?
【发布时间】:2023-03-27 10:28:02
【问题描述】:

如标题中所述,我正在尝试使用 Rails 的 Active Storage 从嵌套在 rails 表单中的元素将图像上传到我的 S3 存储桶。 到目前为止,我已经能够使用 &lt;%= f.input :signature, type: file_field(:user, :signature), %&gt; 使用 Active Storage 上传图像。 Userhas_one_attached :signature。当我使用 file_field 时,图像会正确上传,所以这不是问题的一部分。

到目前为止,我的simple_form 有:

  <div class="signature_pad text-center form-group">
    <div class="signature_pad_heading">
      Enter your Signature:
    </div>
    <div class="signature_pad_body">
      <canvas id="signature_pad_input" height="145px" width="370px" style="height: 145px; width: 370px;" class="border" />
    </div>
    <div class="signature_pad_footer">
      <button type="button" class="btn btn-default" onclick="signaturePad.clear()">Clear</button>
    </div>
  </div>

  <%= f.input :signature, type: file_field(:user, :signature), value: "", as: :hidden %>

  <%= f.submit "Save", class:'btn-primary btn-lg btn-md-wide',  id: "signature_pad_save"  %>

我的 javascript 是:

<script src="https://cdn.jsdelivr.net/npm/signature_pad@2.3.2/dist/signature_pad.min.js"></script>
<script>
const canvas = document.querySelector("canvas");
const signaturePad = new SignaturePad(canvas);

$('#signature_pad_save').click(function(event) {
    if (signaturePad.isEmpty()){
        alert('Please enter your signature.');
        event.preventDefault();
    } else {
        $('#user_signature').val(
            JSON.parse(
                signaturePad.toDataURL()  
        );
    }});
</script>

使用 .toDataURL 我能够获取图像的 base64,我所阅读的所有内容似乎都指出这就是我需要通过 Active-Storage 发送到 S3 的全部内容。

最后:

使用 .file_field 时发送的内容

"signature"=>"<ActionDispatch::Http::UploadedFile:0x007f7a02ad4ef8 @tempfile=#<Tempfile:/tmp/RackMultipart20180903-3527-kked3g.png>, @original_filename="signature1.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"user[signature]\"; filename=\"signature1.png\"\r\nContent-Type: image/png\r\n">},"

当我尝试在表单提交之前插入值时发送的内容

"signature"=>"#<ActiveStorage::Attached::One:0x007f7a01c8b4f0>"}

【问题讨论】:

标签: ruby-on-rails canvas amazon-s3 rails-activestorage signaturepad


【解决方案1】:

是的,这是可能的。

直接上传由DirectUpload 类(或ActiveStorage.DirectUpload,具体取决于您访问内容的方式)处理。通常DirectUpload 需要File 来读取图像,但足够方便,FileBlob,因此您几乎可以使用Blob 代替。 Active Storage 只需要其“文件”中的一些内容,并且几乎所有这些内容都存在于 Blob 中,唯一缺少的是 name 属性,您可以自己添加。

所以现在我们需要从画布中取出Blob。这实际上很容易,因为画布有一个 toBlob method:

HTMLCanvasElement.toBlob() 方法创建一个Blob 对象,代表画布中包含的图像;这个文件可以缓存在磁盘上,也可以由用户代理决定存储在内存中。

首先设置direct uploads as usual。然后为大致如下所示的整体表单添加您自己的提交处理程序:

const form   = your_form_element;
const canvas = your_canvas_element;
const input  = your_file_input;

canvas.toBlob(blob => {
  // Fake out DirectUpload by manually adding a name.
  blob.name = input.files[0].name;

  const uploader = new DirectUpload(blob, input.dataset.directUploadUrl);
  uploader.create((error, blob) => {
    if(error) {
      // Handle the error.
    }
    else {
      // Add the <input type="hidden"> with the signature.
      const hiddenField = document.createElement('input')
      hiddenField.setAttribute('type', 'hidden');
      hiddenField.setAttribute('value', blob.signed_id);
      form.appendChild(hiddenField);

      // And submit away...
      form.submit();
    }
  });
}, 'image/jpeg', 0.95);

假设您需要 JPEG,您可以根据需要使用其他内容类型,也可以将其与原始内容相匹配。我还遗漏了一些常见的提交处理程序样板。如果您设置了通常的全局直接上传处理程序,那么它们将在此处用于进度条等;如果您没有这些,则必须自己处理,上面链接的指南对所有这些都有指示。

【讨论】:

    【解决方案2】:

    我以前也做过类似的事情。我通过imagemagick 通过rmagick gem 将base64 字符串转换回图像文件。

    请参阅此问题的第三个答案以获取代码:How to save a base64 string as an image using ruby

    然后您必须将其添加到控制器的createupdate 方法中,并使用@user.signature.attach 方法,如here 所述。

    【讨论】:

      猜你喜欢
      • 2020-04-30
      • 2014-04-21
      • 2014-10-13
      • 2020-12-01
      • 2020-09-03
      • 2019-11-19
      • 1970-01-01
      • 2020-02-01
      • 1970-01-01
      相关资源
      最近更新 更多