Как я могу загрузить изображение на S3 с Active Storage рельсов из <canvas /> в форме рельсов? - PullRequest
0 голосов
/ 03 сентября 2018

Как указано в заголовке, я пытаюсь загрузить изображение в свою корзину S3 с Active Storage рельсов из элемента, который вложен в форму рельсов. До сих пор я был в состоянии использовать <%= f.input :signature, type: file_field(:user, :signature), %> загрузить изображение с Active Storage. Класс User has_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 образа, и все, что я прочитал, указывает на то, что это все, что мне нужно отправить на S3 через Active-Storage.

Наконец:

Что я отправляю, когда использую .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>"}

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Да, это возможно.

Прямые загрузки обрабатываются классом DirectUpload (или ActiveStorage.DirectUpload в зависимости от того, как вы обращаетесь к вещам). Обычно DirectUpload хочет, чтобы File считывал изображение, но достаточно удобно, File - это Blob, так что вы можете использовать вместо него Blob. Active Storage требует только несколько вещей из своего «файла», и почти все эти вещи присутствуют в Blob, единственная недостающая вещь - это свойство name, и вы можете добавить это самостоятельно.

Так что теперь нам нужно вытащить Blob из холста. Это на самом деле довольно просто, потому что у холстов есть toBlob метод :

Метод HTMLCanvasElement.toBlob() создает объект Blob, представляющий изображение, содержащееся на холсте; этот файл может быть кэширован на диске или сохранен в памяти по усмотрению агента пользователя.

Сначала настройте прямую загрузку как обычно . Затем добавьте свой собственный обработчик отправки для общей формы, который будет выглядеть примерно так:

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, вы можете использовать другие типы контента, если хотите, или можете сопоставить его с оригиналом. Я также пропустил некоторые из стандартных шаблонов обработчиков отправки. Если вы установили обычные глобальные обработчики прямой загрузки, они будут использоваться здесь для индикатора выполнения и т. П .; если у вас их нет, вам придется справиться с этим самостоятельно, руководство, указанное выше, содержит указатели на все это.

0 голосов
/ 05 сентября 2018

Я должен был сделать что-то подобное раньше. Я преобразовал строку base64 обратно в файл изображения через imagemagick через rmagick gem.

См. Третий ответ на этот вопрос для кода: Как сохранить строку base64 как изображение, используя ruby ​​.

Затем вам нужно будет добавить это к create и update методам контроллера и использовать метод @user.signature.attach, как описано здесь .

...