Rails 5: Combine a normal form with vue2-dropzone

1k Views Asked by At

I'm trying to combine a normal form with vue2-dropzone in a Rails 5 app I'm working on.

I think I've almost gotten it to work but the form data isn't being sent across with the Dropzone images.

My _form.html.erb looks a bit like this:

<%= form_for(listing, html: { multipart: true, id: 'listing_form', data: { listing: listing.to_json } }) do |f| %>

  <div class="row">
    <div class="col">
      <div class="form-group">
        <strong><%= f.label :address %></strong><br>
        <%= f.text_field :address, class: 'form-control', 'v-model': 'address' %>
      </div>
    </div>
  </div>

  <!-- Other input fields here -->

  <div class="row">
    <div class="col">
      <h2>Images</h3>
      <vue-dropzone
        ref="listingDropzone"
        id="dropzone"
        @vdropzone-success-multiple="listingRedirect"
        :options="dropzoneOptions">
      </vue-dropzone>
    </div>
  </div>

  <%= f.submit class: 'btn btn-success', 'v-on:click.stop.prevent': 'submitListing' %>

<% end %>

I am submitting the data with the submitListing which I define in a Vue method. That, in turn, calls Dropzone's processQueue which handles the submission. listingRedirect Is then called to perform redirection on success.

if(document.getElementById('listing-multistep') != null) {
  Vue.http.headers.common['X-CSRF-Token'] = document.querySelector('input[name="authenticity_token"]').getAttribute('value');
  var listingForm = document.getElementById('listing_form');
  var listing = JSON.parse(listingForm.dataset.listing);

  const myForm = new Vue({
    el: '#listing-multistep',
    components: {
      vueDropzone: vue2Dropzone
    },
    data: function () {
      return {
        id: listing.id,
        // Other options here...
        address: listing.address,
        dropzoneOptions: {
          url: '/listings',
          method: 'post',
          acceptedFiles: 'image/*',
          uploadMultiple: true,
          autoProcessQueue: false, // Dropzone should wait for the user to click a button to upload
          parallelUploads: 15, // Dropzone should upload all files at once (including the form data) not all files individually
          maxFiles: 15, // this means that they shouldn't be split up in chunks
          addRemoveLinks: true,
          thumbnailWidth: 150,
          maxFilesize: 5,
          dictDefaultMessage: "<i class='fa fa-cloud-upload'></i> Drop files here to upload (max. 15 files)",
          headers: { 'X-CSRF-Token': Vue.http.headers.common['X-CSRF-Token'] }
        }
      }
    },
    mounted: function() {
      // Dropzone actually performs the form submission.
      // Make a PUT request if the listing id exists.
      if(this.id !== null) {
        this.dropzoneOptions['url'] = `/listings/${this.id}`
        this.dropzoneOptions['method'] = 'put'
      }
    },
    methods: {
      submitListing: function() {
        // Do some form processing...

        // listingObj contains the rest of the form data.
        // I'd like to send this object across in the payload.
        var listingObj = {
          address: this.address,
          // more fields...
        }

        this.$refs.listingDropzone.processQueue()
      },
      listingRedirect: function(files, response) {
        window.location = `/listings/${response.body.id}`
      }
    }
  })

I can see the image being sent across in the controller. The problem is that none of the other form data is being sent. What am I doing wrong here?

Thanks in advance!

0

There are 0 best solutions below