Skip to content

fnix/activestorage-resumable

Repository files navigation

Active Storage Resumable

Active Storage Resumable allow you to continue an upload even after a browser restart. Currently it only supports Google Cloud Storage.

This library augments Active Storage direct uploads to support resumable uploads with almost identical semantics. If you already uses direct upload, turn it resumable is straightforward.

Installation

First setup Active Storage to use GCS.

Add this line to your application's Gemfile:

gem 'activestorage-resumable'

And then execute:

$ bundle
$ rails active_storage_resumable:install:migrations
$ rails db:migrate

Resumable uploads

Active Storage Resumable, also includes a JavaScript library, that uploads file in chunks, saving the progress in localStorage, allowing to resume an upload even after a browser restart.

Resumable upload installation

  1. Export an environment variable called UPLOAD_ORIGIN_URL with the upload origin URL, for example 'http://localhost:3000'. You can also create a config/initializers/activestorage_resumable.rb with the following:

    ActiveStorage::Resumable.configure do |config|
      config.upload_origin_url = 'https://mydomain.test:3000'
    end
  2. Include activestorage-resumable.js in your application's JavaScript bundle.

    Using the asset pipeline:

    //= require activestorage-resumable

    Using the npm package:

    require("@fnix/activestorage-resumable").start()
  3. Annotate file inputs with the resumable upload URL.

    <%= form.file_field :attachments, multiple: true, resumable_upload: true %>
  4. That's it! Uploads begin upon form submission.

Resumable upload JavaScript events

Event name Event target Event data (event.detail) Description
resumable-uploads:start <form> None A form containing files for resumable upload fields was submitted.
resumable-upload:initialize <input> {id, file} Dispatched for every file after form submission.
resumable-upload:start <input> {id, file} A resumable upload is starting.
resumable-upload:before-blob-request <input> {id, file, xhr} Before making a request to your application for resumable upload metadata.
resumable-upload:before-storage-request <input> {id, file, gcsBrowserUpload} Before making a request to store a file.
resumable-upload:progress <input> {id, file, progress} As requests to store files progress.
resumable-upload:error <input> {id, file, error} An error occurred. An alert will display unless this event is canceled.
resumable-upload:end <input> {id, file} A resumable upload has ended.
resumable-uploads:end <form> None All resumable uploads have ended.

The events are almost identical to Active Storage direct upload. The bigger difference is in before-storage-request, instead of a XHR, it uses an Upload object from @fnix/gcs-browser-upload. Resumable uploads are transfered in chunks, so it's not very useful to return the XHR of the first chunk. Another small change is in the progress event data, it's not a real ProgressEvent, it's only a faker with the same ProgressEvent properties.

Active Storage extensions

We added three scopes for ActiveStorage::Blob:

  • ActiveStorage::Blob.resumable: Returns all resumable blobs not attached to any model;
  • ActiveStorage::Blob.active_resumable: Returns all unfinished resumable blobs created in the last week (the duration of a resumable session URI). You can use this to show for your users the uploads that can be resumed;
  • ActiveStorage::Blob.expired_resumable: This is most for internal use, we use it to cleanup unfinished resumable blobs.

We also added the instance method uploaded_bytes to ActiveStorage::Blob so you can show to your users the progress of unfinished resumable blobs.

License

The gem is available as open source under the terms of the MIT License.