From Paperclip to Active Storage

Abhishek Kanojia
Jun 3, 2018 · 4 min read

Since the deprecation of paperclip, and release of Active Storage in Rails 5.2, I think it is the right time to learn active storage which provides almost anything that paperclip provided us so far. From creating a style which is called “variant” in case of active storage.

we will start implementing active storage from scratch to our rails application.

Got your laptop/pc ready ??

Let’s start implementing it. I have initialised fresh Rails 5.2 application on my laptop.

Active storage uses two tables named active_storage_blobs and active_storage_attachments.

Run the following command: rails active_storage:install

This will generate a migration: 2018xxxxxxxxxxx_create_active_storage_tables.active_storage.rb that has the code to create two table as mentioned above.

2018xxxxxxxxxxx_create_active_storage_tables.active_storage.rb

For every service that you use for storage Rails 5.2 introduces config/storage.yml for the purposes of storing keys. Have a look at storage.yml below.

config/storage.yml

For local, files storage is defined as: storage folder which is provided in Rails 5.2.

With so many options, provided to use within a single application, you have to specify which one to use in that specific environment.

For development environment, add following line to development.rb

config.active_storage.service = :local

This will tell rails the we will be using local configuration in development environment.

Mirroring can also be used with Rails 5.2 which I will be covering in different tutorial 😉.


Attaching Files to record

Active storage provides a class method has_one_attached which is similar to has_attached_file provided by paperclip.

has_one_attached provided one-to-one mapping between records and files.

So, Let add has_one_attached :avatar to our user model.

models/user.rb

I have created a form to create new user in our application.

new user form

So, to save some time I have created users_controller.rb , users migration with name field users#index and users#new page.

Here is the code for it:

Users listing page with code:

Users listing page.
index.html.erb

Users controller:

Accessing Attached File

Attached file can be accessed by user.avatar , and you can directly use it with image_tag(user.avatar) like so.

Creating variants of attached image.

To enable image processing, you have to include: image_processing gem in Gemfile.

gem 'image_processing', '~> 1.2'

The default processor is MiniMagick but you can use vips .

When the browser hits the variant URL, Active Storage will lazily transform the original blob into the specified format and redirect to its new service location.

<%= image_tag user.avatar.variant(resize: "50x50") %>

Refresh your page your user’s image should be resized to 100 x 100 in size. See the difference in following image.

Original Image (Left) and Cropped Image (Right)

Deleting associated avatar

Deleting associated avatar is as simple as doing:

user.avatar.purge

OR

user.avatar.purge_later

to do it via asynchronous active_job.


Diving little deeper

So, Active Storage works just as fine as any other gem. It does image processing on the fly and saves it storage folder ( in case local disk is defined as storage in storage.yml).

Comparison with other storage solution:

Active Storage uses blob and attachment models backed by Active Record, which is pretty good, that means you don’t need to add columns to existing model’s table.

By looking at the schema.rb file one can easily guess that active storage uses a polymorphic association via Attachment join model which then connects to blob .

schema.rb

See ?? record_type and record_id in active_storage_attachments table.

Lets have a look at the console logs while we are creating a new user instance.

POST /users

So what happens is, as soon as you create a new instance of model User in our case it creates key and checksum of that file , store it into active_storage_blob table.

Then, it creates entry of the associated model i.e user .

Finally, inserts record_id and blob_id to active_storage_attachments table.

Also, notice that it creates an ActiveJob what is this for ?? 🤔

This active job analyses the uploaded file in background and finally updates its metadata, like in the below image:

ActiveStorage::AnalyzeJob

Important Notes

  • Always use purge_later while deleting associated file, purge can be really slow. purge_later will create a job to delete the attachment from blobs table and storage as well.
  • Note that to create a variant it’s necessary to download the entire blob file from the service and load it into memory. The larger the image, the more memory is used. Because of this process, you also want to be considerate about when the variant is actually processed.
  • Active storage creates a get request for each file that you are rendering to the page.

Abhishek Kanojia

Written by

Software Engineer | Ruby on Rails Developer | Geek | Hobbyist | Technology Enthusiast

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade