Lesson Monday

Note: This lesson is a further exploration. You are not required to include ActiveStorage in this section's independent project.

We can easily link to images in a Rails application and we can also store images in the default 1app/assets/images1 directory that Rails provides. However, what if we want to allow users to upload their own images? For instance, we might build an application where a user can add an avatar or a profile picture. And many other applications, ranging from CraigsList to Instagram, allow users to upload and share images.

We can use Rails built-in ActiveStorage to do the same in our own applications.

The example below gives an overview of the steps necessary for using ActiveStorage to add an album cover photo to an Album. If you decide to try to add a profile picture to users in your application instead, be aware that there will likely be additional challenges, especially if you are using Devise. This is because you will likely have a Users table already — but it's mostly being used for authentication purposes. Devise does not make it easy to customize routes — so we recommend exploring ActiveStorage with another table in your database first. Even if you are using Bcrypt, you may run into some customization issues. Be warned... but if you are up for the challenge, go for it!

ActiveStorage is available to us as soon as we create a new application. In fact, you've probably already noticed its fingerprints when running rake routes:

rails_service_blob GET    /rails/active_storage/blobs/:signed_id/*filename(.:format)                               active_storage/blobs#show
rails_blob_representation GET    /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET    /rails/active_storage/disk/:encoded_key/*filename(.:format)                            
active_storage/disk#show
update_rails_disk_service PUT    /rails/active_storage/disk/:encoded_token(.:format)                                      active_storage/disk#update
rails_direct_uploads POST   /rails/active_storage/direct_uploads(.:format)                                         active_storage/direct_uploads#create

To use ActiveStorage, start with the following command in the root directory of the project:

rails active_storage:install

Rails will automatically provide the necessary routes, models and tables to add images to any class. Take a look at the schema. ActiveStorage specifically adds two tables: active_storage_blobs and active_storage_attachments. Metadata is stored in the former while the actual images (or other files) are stored in the latter. For development applications, this storage will likely be on local disk (your computer), but ActiveStorage can also be configured to use Amazon S3 and other services, which you'll likely want to use if you decide to deploy an application with ActiveStorage.

The default configuration for ActiveStorage is to use the local disk, but the configuration can be changed in config/storage.yaml.

Once ActiveStorage is fully configured, adding images is as simple as doing the following:

class Album < ApplicationRecord
  has_one_attached :album_cover_photo
end

ActiveStorage takes care of the rest.

To include an option to upload a photo, we can add the following line to a form:

<%= f.file_field :album_cover_photo, %>

Then, in the AlbumsController's create action, we need to use the attach() method to actually attach the photo to the proper album. The code for adding a photo will look something like this:

@album.album_cover_photo.attach(params[:album][:album_cover_photo])

If necessary, use binding.pry to troubleshoot which params you will need.

Don't forget to add strong params for album_cover_photo in the controller.

Then, assuming that we can access @album in a view, we could access the picture using an image_tag like this:

<% if @album.album_cover_photo.attached? %>
  <%= image_tag @album.album_cover_photo %>
<% end %>

We can use the attached? method to check to see if @album actually has an album_cover_photo. Then we can use a standard image_tag to actually show the photo.

Note that ActiveStorage can be used for any type of file storage, not just images. However, images are a common use case. For more information on ActiveStorage, see the official Rails documentation. Using ActiveStorage is not required for this section's project, but we highly recommend exploring this feature.

Lesson 14 of 27
Last updated August 7, 2022