New webinar: "The Remote Job Search: My Microverse Journey" with graduate Paul Rail
Watch Now

File uploading is an important aspect of many Ruby on Rails applications. The Paperclip gem was long seen as the go-to solution for this functionality. However, with its recent deprecation, Active Storage is now the go-to source for enabling file uploading within Rails applications. Active Storage is an aspect of Rails that allows users to upload files in various environments and to various cloud storage services. These services include Amazon’s S3 service, Google Cloud Storage, and Microsoft Azure Storage service. It also provides a local-disk based service that can be used in the application development stage. Images are one of the file types that Active Storage can store and are the focus of this quick, step-by-step tutorial.

In order to set up Active Storage within your project, enter the following commands to cd into the project directory, and install the service:

<> $ cd 
$ rails active_storage:install <>

This creates a migration file that will introduce two tables into the application’s database once migrated, called, “active_storage_blobs” and “active_storage_attachments” as seen below.

create_table "active_storage_attachments", force: :cascade do |t|
  t.string "name", null: false
  t.string "record_type", null: false
  t.bigint "record_id", null: false
  t.bigint "blob_id", null: false
  t.datetime "created_at", null: false
  t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
  t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
create_table "active_storage_blobs", force: :cascade do |t|
  t.string "key", null: false
  t.string "filename", null: false
  t.string "content_type"
  t.text "metadata"
  t.bigint "byte_size", null: false
  t.string "checksum", null: false
  t.datetime "created_at", null: false
  t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true

Once migrated, you can configure the storage services your application uses by editing the storage.yml file in the config folder. By default, Active Storage utilizes the local disk for storage.

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

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

You can use different storage services in each environment (test, development and production) by editing the appropriate line in the environment config files to match your desired service. For example, if you configured the Google Cloud storage service to utilize it in production, ensure that the following line exists in your config/environments/production.rb file:

config.active_storage.service = :google

For an in-depth look at how to configure these cloud services in your rails app, check out this article by Wiktor Plaga.

Image Uploading

Once your storage service is properly configured, you can move forward with implementing the necessary logic for uploading an image. No additional model is required. 

In the case of an app where the user wants to associate images with their articles, the following configuration can be made to the appropriate model:

class Article < ApplicationRecord
belongs_to :user
has_one_attached :image

This macro “has_one_attached” enables one-to-one mapping between each Article record and the image file. The symbol that follows can be given any name. However, once that name is specified, it will have to be used in all subsequent application logic for image uploading. If you implemented a private params method for model creation, pass the named symbol to the params method as follows:

class ArticlesController < ApplicationController

    [your other controller actions here]

def article_params
  params.require(:article).permit(:title, :content, :image)

In order to enable the mapping of multiple images to each record, add the line below instead. It’s important to note that the symbol passed to the macro must be pluralized in this instance.

class Article < ApplicationRecord
belongs_to :user
has_many_attached :images

Once these simple configurations are made, you can go ahead and implement a form that allows users to attach an image file. The same symbol passed to the macro in the model must be passed to file_field form helper:

<%= form_with model: @article, method: "post" do |f| %>
    <%= f.text_field :title, placeholder: 'Enter article title here' %>
    <%= f.file_field :image %>
    <%= f.text_area :content, placeholder: "Enter article content here", size: "70x20" %>
    <%= f.submit "Post" %>
<% end %>

Once the user completes the form and hits send, the image will be uploaded and the credentials stored in the database. Upon uploading the image, you can incorporate it into the flow of the post in different ways. You can conditionally attach the image as follows:

<% if article.image.attached? %>
  <img src="<%= (url_for(article.image)) %>">
<% end %>

You can also apply that image as a background:

<div style="background-image: url(<%= (url_for(@article.image)) %>)">

Seeding Images in Your Rails Database

Rails also enables users to seed the database with images if they want. To do so, you can use the ‘attach’ method, passing in a hash with two keys. The ‘io’ key calls the open method on the File class and takes the image’s relative path as an argument. 

user = User.create(
first_name: Faker::Name.first_name,
last_name: Faker::Name.last_name,
email: Faker::Internet.safe_email,
password: '123456789'
article = Article.new(
title: Faker::Lorem.sentence(word_count: 5),
content: Faker::Lorem.paragraphs(number: 4),
article.user = user
io: File.open('app/assets/images/news.jpg'),
filename: 'nw.jpg'

Rails also provides some basic methods that can be used on the console to interact with the image records. The ‘attached?’ method can be used to determine if a particular object has an associated attachment. To call this method, run the following commands to open the console and query the database. The ‘attached’ method returns a Boolean response.

$ rails console

$ article.image.attached?
# False

Deleting Attached Images

Rails also provides two methods for deleting attached images from the database. The ‘purge’ and ‘purge_later’ methods are used for this purpose. They are synchronous and asynchronous respectively and can both be called in the rails console. Please note that associated images are automatically deleted from storage if the record it was associated with has been deleted. eg. deleting an article, also deletes its attached images. There is no need to add ‘dependent: :destroy’ to the model to allow this behavior.

And there you have it! I hope this is helpful, in showing how to add a feature in your Rails app, so your users can upload images. Happy coding!

To learn more about Microverse, and joining our supportive community of remote software developers, get started here!

More from Our Blog

You Might Also Like

See All Posts
Subscribe to our Newsletter

Get Our Insights in Your Inbox

Career advice, the latest coding trends and languages, and insights on how to land a remote job in tech, straight to your inbox.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.