Recently, I had to figure out how to create an Image Uploader for a Ruby on Rails application. I had used Paperclip before, so I looked into that, but quickly discovered that Rails 5.2 has
Active Storage built into it.
What is ActiveStorage? It's a built-in feature in Ruby on Rails that allows for uploading files to third-party storage (i.e., Amazon S3, Google Cloud Storage, etc.) while saving these images to Active Record objects.
And, as long as you're on at least Rails 5.2 - this is important because this is the the version of Rails that introduced
ActiveStorage - the process for getting up and running, for me at least, is and was incredibly smooth.
To start, go into your rails application in the terminal and type:
rails active_storage: install
This command runs a migration that adds two new tables to your database:
Here's a helpful image I found to describe these tables:
(image is from this amazing article which you should read if you have a chance).
Make sure to run
rails db:migrate to run the migration.
Now that we're set up with the tables in our database, the next step is setting up where we want to store our files that we upload. Go ahead and create this file:
In it, we need to specify where we want to store our files that we upload for our
development environment, our
test environment, and our
The file should look something like this:
local: service: Disk root: <%= Rails.root.join("storage") %> test: service: Disk root: <%= Rails.root.join("tmp/storage") %> amazon: service: S3 access_key_id: "" secret_access_key: "" bucket: "" region: "" # e.g. 'us-east-1'
You don't have to set this up for each environment, however, if you have multiple environments, it is likely that they will each store uploads in a different place so it's good to get this configured. Part of what makes Active Storage so great is that it comes with disk storage for your development and test environments. For production, depending on which service you use, you can configure that to be set up in this file (I chose Amazon S3 above, but have not filled in any of the credentials).
With this in place, we then need to tell Active Storage which service to use and we'll do that on a per-environment basis, too.
config/environments/development.rb let's add:
config.active_storage.service = :local
which means we'll store files locally for our development environment.
config/environments/test.rb let's add:
config.active_storage.service = :test
which means we'll temporarily store files locally (notice in the above
config/storage.yml file that we're storing to the
tmp/storage directory and not the
And, lastly, in
config/environments/production.rb let's add:
config.active_storage.service = :amazon
which means we'll store our files on Amazon.
With all of this set up, we have two more major steps: Attaching the files to our Model and displaying that attached file to the user in our UI.
To attach the file to our model: use the
has_one_attached relationship to set up a one-to-one mapping between the record and the files; or, use the
has_many_attached relationship to set up a many-to-one mapping between the record and the files.
A user has one uploaded image associated with it.
class User < ApplicationRecord has_one_attached :image end
A Blog Post has many uploaded images associated with it.
class Post < ApplicationRecord has_many_attached :images end
NOTE: to see how to fully set up the
has_many_attached association see the docs. To keep things simple, I'll set up the UI using the
Finally, to allow users to upload the images in the UI and then display the image back to the user, we can add an upload form field to our page by adding this:
<%= form.file_field :image %>
:image param into your params that you permit in the controller; for example:
def user_params params.require(:user).permit(:email, :password, :image) end
With this in place, we can display the image back to a user (if there is one attached) so that they can see their attached file (in the
user#show part of the application):
<% if @user.image.attached? %> <img src="<%=(url_for(@user.image)) %>"> <% end %>
attached? is a helpful built-in method that tells us if the image for that user has been attached. You can also call
attach on an existing user to attach an image to that user by doing:
And, there you have it! A way to add an image uploader to your rails application using the built-in Rails Active Storage 🎉