Question about using Dashboard with Rails form

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?