How to Integrate AWS S3 with a Rails Project for File Uploads

Kauana Tombolato - Sep 9 - - Dev Community

If you want your Ruby on Rails application to handle files, such as images, videos, PDFs and etc, you are in the right place.

First, let's understand:

What's Active Storage?

Active Storage is a tool that facilitates file uploads to cloud storage services, such as Amazon S3 (which we will use in this project), Google Cloud Storage, or Microsoft Azure, and attaches these files to Active Record objects. It also comes with a local disk-based service for development and testing and supports file mirroring to subordinate services for backups and migrations.

Before installing Active Storage in your application, it is necessary to install some third-party software for file analysis and processing support. Here is the list of necessary software:

  • libvips v8.6+ or ImageMagick: for image analysis and transformation.
  • ffmpeg v3.4+: for video previews and ffprobe for video/audio analysis.
  • poppler or MuPDF: for PDF previews.
  • Additionally, it is necessary to add the image_processing gem if your application will use image files.

I'll walk you through installing Active Storage by building an application together.

So, let's create the application!

Step 1: Create Your Rails Project

rails new name_project
Enter fullscreen mode Exit fullscreen mode

Creating an application


Step 2: Configure AWS SDK in Your Project

  • Add the following to your Gemfile:
# Gemfile
gem 'aws-sdk-s3'
Enter fullscreen mode Exit fullscreen mode
  • Then, in your terminal, run:
bundle install
Enter fullscreen mode Exit fullscreen mode

This will install all the necessary packages, including the new one we just added.

Installing new gem


Step 3: Add Active Storage to the Project

Run the following commands to install Active Storage and create the necessary tables:

rails active_storage:install
rails db:migrate
Enter fullscreen mode Exit fullscreen mode

This will generate a migration to create the active_storage_blobs and active_storage_attachments tables.
Generate new tables

Verification:

After running these commands, verify that the tables were created correctly in the database. You can do this by accessing the Rails console and inspecting the tables:

  • Open the Rails console:
rails console
Enter fullscreen mode Exit fullscreen mode
  • Check that the required Active Storage tables were created:
ActiveRecord::Base.connection.tables
Enter fullscreen mode Exit fullscreen mode
  • You should see the following tables listed: active_storage_blobs active_storage_attachments active_storage_variant_records

Verifying tables


Step 4: Create the S3 Bucket

Follow this article : How to create a bucket in AWS S3?


Step 5: Configure Secure Credentials

You can do this using environment variables or your credentials file. In this example, we'll use a .env file.

#.env
AWS_ACCESS_KEY_ID="your-key-id"
AWS_SECRET_ACCESS_KEY="your-secret-access-key"
AWS_REGION="bucket-region"
S3_BUCKET_DEVELOPMENT="bucket-name"
Enter fullscreen mode Exit fullscreen mode

Make sure to replace the placeholders with your actual values.


Step 6: Configure File Uploads in Rails

Add the following configuration to your config/storage.yml:

# config/storage.yml
amazon:
  service: S3
  access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
  region: <%= ENV['AWS_REGION'] %>
  bucket: <%= ENV['S3_BUCKET_DEVELOPMENT'] %>
Enter fullscreen mode Exit fullscreen mode

Note: You can create different names for each bucket configuration. In this example, we are using "amazon", but you might use names like "amazon_development" or "amazon_production" to make it more readable and easier to manage multiple environments. This approach helps you distinguish between configurations for different environments.


Step 7: Update the Storage Service in the Environments

Update the storage service for the necessary environments. In this case, we'll do it for the development environment.

# config/environments/development.rb
config.active_storage.service = :amazon
Enter fullscreen mode Exit fullscreen mode

Note: It's important to configure the storage service for each environment (development, test, and production) to ensure that your application works correctly in all scenarios.


Step 8: Implement File Uploads in a Model

As an example, let's create a Post model that includes text content and an attached image. In this illustration, we will allow a single image file to be attached to a post.

First, note that you don't need to include a column for the image in the Post model's database migration. Active Storage will handle the storage of the image data in separate tables.

Add the following to your model to enable file uploads:

# app/models/post.rb
class Post < ApplicationRecord
  has_one_attached :image
end
Enter fullscreen mode Exit fullscreen mode

Other Possible Attachments:

Single File Attachments: You can attach a single file to a record using has_one_attached as shown in the example. This is useful for models that require only one file attachment, such as a profile picture or a single document.

Multiple File Attachments: If you need to attach multiple files to a single record, you can use has_many_attached. This is useful for models that need to handle multiple files, such as an album with multiple photos, documents or a post with multiple attachments.


Step 9: Accept Attribute :image in Controller

To handle file uploads, you need to permit the :image attribute in the controller. This allows the form to submit the file to your model.

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  # other actions (index, etc.)

  def create
    @post = Post.new(post_params)
    if @post.save
      redirect_to @post, notice: 'Post was successfully created.'
    else
      render :new
    end
  end

  private

  def post_params
    params.require(:post).permit(:content, :image)
  end
end
Enter fullscreen mode Exit fullscreen mode

This ensures that the :image attribute is accepted when creating or updating a post.


Step 10: Create a Form to Handle File Uploads

Add a file field to your form for uploads:

<!-- app/views/posts/new.html.erb -->
<%= form_with(model: post, local: true) do |form| %>
  <!-- another fields in the form -->
  <div class="field">
    <%= form.label :image %>
    <%= form.file_field :image %>
  </div>
  <%= form.submit %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

Step 11: Display the Uploaded File in the Post

Modify your view to display the uploaded file:

<!-- app/views/posts/index.html.erb -->
<p>
  <strong>Image:</strong>
  <%= image_tag post.image if post.image.attached? %>
</p>
Enter fullscreen mode Exit fullscreen mode

Improving:
Add a link to download the image and specify the size:

<!-- app/views/posts/index.html.erb -->
<p>
  <strong>Image:</strong>
  <% if post.image.attached? %>
    <%= link_to image_tag(post.image, size: "200x200", alt: "image file"), rails_blob_path(post.image, disposition: "attachment") %>
  <% end %>
</p>
Enter fullscreen mode Exit fullscreen mode

Step 12: Test the Upload

To ensure that file uploads are working correctly, follow these steps for verification:

Check Database Records:

  • Open the Rails console:
rails console
Enter fullscreen mode Exit fullscreen mode
  • Verify that the active_storage_blobs and active_storage_attachments tables contain the expected records:
ActiveStorage::Blob.last
ActiveStorage::Attachment.last
Enter fullscreen mode Exit fullscreen mode

Verifying corrected upload on Terminal

Check on AWS Bucket:

Checking on AWS Bucket the file uploaded

Code repository: Upload_file_s3


References:

For more information on Active Storage, please access to the official Active Storage Overview web site.

. .