Ruby on Rails

Using Ruby on Rails Active Storage on Digital Ocean

Active Storage is a new feature of Ruby on Rails 5 for handling image and file attachments. It replaces the need for using external image handing gems such as tried and sturdy Paperclip, which is now deprecated, with the maintainer recommending using Active Storage. So there you go, it's time to move on. Active Storage has been well thought through, with a very clean implementation, allowing for much greater on-the-fly flexibility, rather than strict advance determination of image sizes.

In this post, I'll show you how to configure Active Storage, using Digital Ocean (referral link) Spaces as the file store.

Setup

Active Storage uses two tables to manage storage: active_storage_blobs, and active_storage_attachments. Once you have upgraded to at least Rails version 5.2, you can run a generator and migrations for these files:

rails active_storage:install
rails db:migrate

Defining the storage services you will use is done in config/storage.yml. Here we have added the definition for digitalocean and you should notice that the service type is S3, which conveniently enough is the same as Digital Ocean, so these instructions will work for either service.

First, you will need credentials to use Digital Ocean Spaces, go to API > Spaces Access Key > Generate New Key. With the credentials, we will store them using Rails custom credentials

Once you have the credentials, modify config/storage.yml:

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

digitalocean:
  service: S3
  endpoint: <%= Rails.application.credentials.digital_ocean[:endpoint] %>
  access_key_id: <%= Rails.application.credentials.digital_ocean[:access_key_id] %>
  secret_access_key: <%= Rails.application.credentials.digital_ocean[:secret_access_key] %>
  region: <%= Rails.application.credentials.digital_ocean[:region] %>
  bucket: <%= Rails.application.credentials.digital_ocean[:bucket] %>

Failure to set any of the credentials will tend to yield an error:

Unable to autoload constant ActiveStorage::Blob::Analyzable

Defining which service to use in specific environment files, ie. config/environments/development.rb, which is this case is to use digitalocean in development.

config.active_storage.service = :digitalocean

Since we are going to use Digital Ocean, we need to add the AWS gem aws-sdk-s3:

gem "aws-sdk-s3", require: false

Attaching Files

For attaching files, you have a choice to either attach one (hasone) or many (hasmany) to a model, in this case User:

class User < ApplicationRecord
  has_one_attached :avatar
end

In the form, you can simply add:

<%= form.file_field :avatar %>

And to see if an image is attached?

user.avatar.attached?

In the case of a has_many relationship:

class User < ApplicationRecord
  has_many_attached :images
end

And to add additional images:

@users.images.attach(params[:images])

Removing Images

To remove all of the attached images:

user.avatar.purge

Transforming Images

Additional Image Transformation Setup

To be able to use variants of your original images, you need to add the image_processing gem to your Gemfile, which will by default incorporate and use MiniMagick under the covers, but you can use other processors as well such as Vips.

gem 'image_processing', '~> 1.2'

I did my install using the Digital Ocean Ruby on Rails Ubuntu image, which needs ImageMagik, installed with:

sudo apt-get install imagemagick

Variants

For handling variants, when the browser requests a variant url, Active Storage will lazily transform the original BLOB into the requested format:

<%= image_tag user.avatar.variant(resize_to_fit: [100, 100]) %>

Carson R Cole