Rails 5.2: ActiveStorage highlight

May 17, 2018 | Alexandre Ferraille | 5-minute read

Rails 5.2 was released a few weeks ago and comes with awesome features like the new credentials vault, HTTP/2 early hints, Redis cache store and ActiveStorage, which I’m going to focus on in this blog post. The project was initiated by DHH in mid-2017 and has been merged into Rails core. It’s a built-in way to deal with uploads without extra dependencies like Paperclip, Carrierwave or Shrine.

How does it work?

ActiveStorage comes with a complete DSL which allows you to attach and detach one or multiple files to a model. By default, ActiveStorage isn’t installed in a new rails project, you have to run:

rails active_storage:install

This command simply copies a migration in your projet. ActiveStorage needs two models/tables : active_storage_blobs where each record represents a file (which is not stored in the database of course) and active_storage_attachments is a polymorphic bridge between your models and your uploaded files.

In your model, you need to declare that you’re attaching files:

class Car < ApplicationRecord
  has_one_attached :photo

Then, you can add a file input into your form:

<%= image_tag url_for(car.photo) if car.photo.attachment.present? %>
<%= form.label :photo %>
<%= form.file_field :photo %>

In your controller, you must specify that you want to attach a file:

@car.photo.attach(params[:car][:photo]) if params[:car][:photo]

And that’s all you need to do for a basic file uploader. If you attach a new file or you delete your record, ActiveStorage will remove the old one from your storage and clean up your database.

ActiveStorage goes further still

With a lot of nice little “cherries on the cake”, ActiveStorage covers most of the cases:

  • Storage: A few lines of configuration are enough to store/mirror your files into AWS S3, Microsoft Azure or Google Cloud. And if you’re using a more funky storage provider, you can extend the ActiveStorage::Service class.
  • Direct upload: A complete JavaScript library has been written for ActiveStorage which allows you to directly upload to your storage bypassing the rails backend. It comes with a lot a JavaScript events to easily plug this feature with common libraries such as TinyMCE, DropZoneJS…
  • Image post-processing: A common need when uploading images is to create resized variants from the original. ActiveStorage works by default with MiniMagick, which is a Ruby implementation for ImageMagick.
  • Video and PDF previews: With external libraries (ffmpeg and mutool), you can get a preview from a file without downloading it entirely.

What’s the difference with other upload managers?

Maintenability: Since ActiveStorage has been merged into Rails, all the features described above are built-in and don’t require any extra dependencies and so less maintenance needs to be scheduled.

Structure: Most popular gems like Shrine, Paperclip, etc. don’t provide ready-to-use tables and require a migration to add a few fields where you want to store your file information. Even if you feel free to do what you want and you’re not stuck to the ActiveStorage way, from my experience you’ll certainly recreate a polymorphic Asset model.

Form: As we seen above, ActiveStorage attaches and detaches files outside ActiveRecord transactions. You need to do it by yourself when you need to, independently from a save, whereas common gems store your files using ActiveRecord callbacks directly from your params. In my opinion, ActiveStorage provides a better way to handle file attachments by separating two concepts: attributes which go in the database and files which depend on your storage.

Missing features: There’s a few advanced features which are not handled by ActiveStorage (yet?) and you’ll need to develop them if you choose to go with ActiveStorage. For instance, Shrine (currently the most advanced competitor), provides a way to cache uploaded files and avoid re-upload when your form has errors. Shrine also provides a simple way to manipulate and post-process files in the background. And last but not least, the implementation of TUS protocol allow you to do multi-part uploads.

What does the future have in store for them?

It’s really interresting to see that Thoughbot (the Paperclip maintainers) just announced the deprecation of Paperclip in favor of ActiveStorage and it’s a good example of what makes the Ruby On Rails community so strong.

We can be sure they’ll use their experience by contributing to ActiveStorage, as did janko-m (Shrine maintainer) who already improved S3 storage and implemented his own ImageProcessing gem to ActiveStorage.

How we handle file uploads at Drivy

At Drivy we handle file uploads in a similar way to ActiveStorage. We have our own DSL for models and a lot of methods for controllers and views. We also have some JavaScript for direct upload to our cloud storage. We don’t use post processing libraries for our images and we delegate all these tasks to a third party in order to reduce the impact on our CPUs.

So, should we move to ActiveStorage? We already have all the features we need and there’s currently no need to move to ActiveStorage. Sure it might reduce the maintenance cost and we could take advantage of security fixes and evolution with Rails upgrades, but with a 6-year-old codebase and thousands of attachments the migration would be huge!

In my opinion, ActiveStorage is a really good choice for a new project.

EDIT: janko-m (Shrine maintainer) commented this post via reddit and raised interesting points related to ActiveStorage and future changes for Shrine.

👍  Like this post? Join Drivy's engineering team! View openings