Rails with Uppy XHRUpload: How to get the @model into the params hash?

Hello!

I’m trying to get Uppy jiving with a Rails upload form, but I’m having trouble getting it setup properly. The resulting params hash is missing its initial :image object. In a typical Rails form, I assume this is taken care of whenever its bound to a model instance. But I’m not sure how to do something like that with an Uppy form.

Just thinking out loud here, but maybe it has something to do with how I’m setting the endpoint option?

And to clarify, I’m just trying to get it setup for a development environment, using localhost:3000 and storing everything locally for now

Thanks in advance for any help or insights!

Here’s the “standard” Rails form (withOUT uppy):

<%= form_for @image, html: { multipart: true } do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

  <div class="field">
    <%= f.label :file %><br>
    <%= f.file_field :file %>
  </div>
  <div class="actions">
    <%= f.submit "Upload Images" %>
  </div>
<% end %>

And its resulting params hash:

=> <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"Cr9NAN6NE9JV6HrI7RE7EmjmxqnlfbWk+LT5k9yLuq1Sm0L9E/zJ/eXCDcjbyw7A6lUHP2LFBqbfjY+SWoeO+w==", "image"=>{"file"=>#<ActionDispatch::Http::UploadedFile:0x000055d297d74168 @tempfile=#<Tempfile:/tmp/RackMultipart20200328-12356-1qjsycd.png>, @original_filename="Screenshot from 2019-07-22 04-24-23.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"image[file]\"; filename=\"Screenshot from 2019-07-22 04-24-23.png\"\r\nContent-Type: image/png\r\n">}, "commit"=>"Upload Images", "controller"=>"images", "action"=>"create"} permitted: false>

And here’s my attempt at an Uppy form:

<%= form_for @image, html: { id: "uppy-form" } do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

  <%= f.hidden_field :file, multiple: true, name: "images[file]", value: @image.file_data,
    accept: 'image/jpg,image/jpeg,image/gif,image/png,image/tif,image/tiff', class: "upload-hidden" %>

  <%= hidden_field_tag :authenticity_token, form_authenticity_token, id: :form_token %>
<% end %>

<script>
  const XHRUpload = Uppy.XHRUpload

  var uppy = Uppy.Core()
    .use(Uppy.Dashboard, {
      inline: true,
      target: '#uppy-form'
    })
    .use(XHRUpload, {
      endpoint: '/images',
      fieldName: 'images[file]'
    })
    .setMeta({
      authenticity_token: $("#form_token").attr('value')
    })

  uppy.on('complete', (result) => {
    console.log(`Upload complete! We've uploaded these files:`, result.successful)
  })
</script>

The resulting error when calling $ params

Completed 400 Bad Request in 5328ms (ActiveRecord: 0.4ms | Allocations: 40383)
ActionController::ParameterMissing - param is missing or the value is empty: image:

And the params in full

=> <ActionController::Parameters {"authenticity_token"=>"CYUz9AszYR4G0WEiI4bDoOlUyH4jFMzAVRf4vF6m6OJRoTwJxkK7Mbb7FiIVXPZya+cJ6KSsf8JyLo692KrctA==", "relativePath"=>"null", "name"=>"Screenshot from 2019-07-10 06-34-34.png", "type"=>"image/png", "exifdata"=>"[object Object]", "images"=>{"file"=>#<ActionDispatch::Http::UploadedFile:0x000055d2962c49d0 @tempfile=#<Tempfile:/tmp/RackMultipart20200328-12359-1d093y1.png>, @original_filename="Screenshot from 2019-07-10 06-34-34.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"images[file]\"; filename=\"Screenshot from 2019-07-10 06-34-34.png\"\r\nContent-Type: image/png\r\n">}, "controller"=>"images", "action"=>"create"} permitted: false>

In the ImagesController, here is how image_params is defined. It’s that initial .require(:image) that I think is missing when it gets sent over:

def image_params
  params.require(:image).
    permit(...)
end

Nevermind, I just figured it out!

Turns out I had a typo in the fieldName. It should be image[file]