I’m having a lot of trouble getting Uppy to work with my Rails form, and I’m hoping someone can help me untangle my thought process.
I want to be able to submit an image that a user uploads (or takes with webcam), but I need for the form contents (a json string) to be encryptable. So that string needs to be a file-like object.
A regular file submission (without Dashboard/Webcam) takes hidden_field :image, value: @photo.cached_image_data
and a file_field :image
selection in the form, then does this in console when saved:
"photo"=>{"image"=>#<ActionDispatch::Http::UploadedFile:0x00007fe0fef3de78 @tempfile=#<Tempfile:/var/folders/hj/g_90jx_n7s58m73qlf9h0c4w0000gn/T/RackMultipart20210313-97062-1pd54fh.jpg>, @original_filename="test.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"photo[image]\"; filename=\"test.jpg\"\r\nContent-Type: image/jpeg\r\n">}
Note that ActionDispatch::Http::UploadedFile
object. The image is uploaded to S3 and the record is saved to the db upon submit. Encrypting image
is super easy.
Replacing the file field with Dashboard/Webcam adds a handful of complications. For example, if I want the upload data to be appended to the form, the doc says to set the Form target attribute to something on the form or a child of the form. So, doing this in js:
document.addEventListener('turbolinks:load', () => {
document.querySelectorAll('.upload-file').forEach(fileInput => {
fileUpload(fileInput)
})
})
.use(Dashboard, {
inline: true,
target: '#file-uppy',
trigger: '.upload-file',
hideUploadButton: true,
replaceTargetContent: false,
})
uppy.use(Form, {
target: '.upload-data',
addResultToForm: true,
multipleResults: true
})
and this in my form
<%= form_for @photo, url: onboard_add_photo_path do |f| %>
<div class="upload-file"></div>
<div id="file-uppy"></div>
<%= f.hidden_field :image, class: "upload-data" %>
<% end %>
And then submit that, the image
gets submitted as a json string, not a File object:
Processing by Users::IdDocsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"[FILTERED]", "photo"=>{"image"=>"{\"id\":\"6536f20f163a67f5b432d250351eac7c.jpg\",\"storage\":\"cache\",\"metadata\":{\"size\":55368,\"filename\":\"cam-1615814031784.jpg\",\"mime_type\":\"image/jpeg\"}}"}, "commit"=>"Upload"}
The image
in this request goes to S3. File encryption works with IO objects, not strings, and image
is a string. So if I take image
and go like StringIO.new(image)
to make the json string conform to a file structure, the resulting file that gets uploaded is broken. Encrypted, but the setup that happens prior to the json->file conversion is most likely incomplete.
Any thoughts?