Ask A Question

Notifications

You’re not receiving notifications from this thread.

How do I upload files with ActiveStorage and Vue.js?

Taylor Cooney asked in Rails

Hey GoRailers,

Stemming from the Rails & Vue.js Trello Clone, I'm looking to add file uploads to a Card model using the new Rails 5.2 ActiveStorage feature. I'm stronger in Rails - previously I would use Paperclip to handle this. I've setup the config/storage.yml file and necessary migrations for ActiveStorage. I've also set the association between on the Card and updated the CardController to permit files: [].

The card.vue component built from the tutorial currently works well; a Card can have a title and description, and the description can be updated. These records persist to the database. My problem is figuring out how to bind file uploads to the card, and the logic required to upload multiple files on save.

Currently I'm using <input name="files" type="file" data-direct-upload-url="/rails/active_storage/direct_uploads" direct_upload="true" /> to create the input field in the card. However, after selecting a PDF image from my local machine and clicking save, the logs show that nothing happens [in regards to inserting a new row in active_storage_attachments or creating a blob]. How can I expand the save method to accept the file? Is the input field sufficient to bind the element?

card.rb

class Card < ApplicationRecord
  has_many_attached :files
end

CardController

class CardsController < ApplicationController
  private
    def card_params
      params.require(:card).permit(:list_id, :title, :position, :description, files: [])
    end
end

card.vue

<template>
    <div>
        <div @click="editing=true" class="card card-body">
            <h4>
                {{card.title}}
            </h4>
        </div>

        <div v-if="editing" class="modal-backdrop show"></div>

        <div v-if="editing" @click="closeModal" class="modal show" style="display: block">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <div>
                            <h4>
                                {{card.title}}
                            </h4>
                        </div>
                    </div>
                    <div class="modal-body">
                        <div>
                            <h5>{{card.description}}</h5>
                        </div>
                        <textarea v-model="description" class="form-control"></textarea>
                    </div>
                    <div class="modal-footer">
                        <input name="files" type="file" data-direct-upload-url="/rails/active_storage/direct_uploads" direct_upload="true" />
                        <button @click="save" type="button" class="button button-secondary">Save changes</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>

export default {
    props: ["card", "list"],

    data: function() {
        return {
            editing: false,
            title: this.card.title,
            description: this.card.description,
            files: []
        }
    },

    methods: {
        save: function() {
            var data = new FormData
            data.append("card[title]", this.title)
            data.append("card[description]", this.description)

            Rails.ajax({
                url: `/cards/${this.card.id}`,
                type: "PATCH",
                data: data,
                dataType: "json",
                success: (data) => {
                    const list_index = window.store.lists.findIndex((item) => item.id == this.list.id)
                    const card_index = window.store.lists[list_index].cards.findIndex((item) => item.id == this.card.id)
                    window.store.lists[list_index].cards.splice(card_index, 1, data)

                    this.editing = false
                }
            })
        }
    }
}
</script>
Reply

Has anyone had any success with Vue and ActiveStorage in the past? I could really use some assistance in refactoring the form to handle file uploads.

Reply

Still looking for some assistance here 😅

Reply

I think it should be FormData() and not FormData. By just using FormData...it will return you the function.

You need to go through this documentation.
Direct Uploads in Rails

The thing which is missing from the code is that you are just sending the title and description to your PATCH method in the cards controller. You are not sending any file related things like the signed ID for the blob of the file which you uploaded to the cloud server. Hence the database is not showing any uploads related information.

You should look at this discussion which might be helpful in understanding how direct upload works

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 85,376+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.