Rails Active Storage

Learn via video courses
Topics Covered

Overview

In today's world, storing and managing large amounts of files is an essential part of many web applications. Without proper management, this can lead to bulky databases and slow response times. Rails Active Storage is a solution that helps developers manage file uploads and downloads efficiently. In this article, we will explore the basics of Active Storage and how to set it up in a Rails application, with a focus on attaching and removing files. We will also cover testing and direct uploading.

What is Active Storage in Ruby on Rails?

Rails Active Storage is a built-in feature of Ruby on Rails that helps manage file uploads and downloads in web applications. It's a way for developers to easily store and retrieve files like images, videos, and PDFs. With rails active storage, you can keep your application's database from becoming bloated with files, which can slow down your website's performance. Instead, files are stored separately from your database, making it easier to manage and scale. Active Storage can also be configured to work with various cloud storage services like Amazon S3 and Google Cloud Storage. This makes it easy to store large amounts of files without worrying about running out of disk space on your server.

Note: Below is the application flow when the rails application loads. It is important to have a clear view of the workflow.

view of the workflow

  • Rails starts up and loads the environment files for the current environment (such as config/environments/production.rb or config/environments/development.rb). It then loads the configuration for that environment, connects to the database, and loads any necessary service providers.
  • Once all the necessary components are loaded, Rails initializes the middleware and starts the application. It then loads the routes and begins handling requests.

Setting Up Rails Active Storage

To get started with the web application locally, any uploaded images will be saved to our computer's hard drive. However, when we deploy the app to a Heroku server for production, the images will be saved to an Amazon S3 bucket instead.

  • Installing rails active storage:
    1. To install rails active storage we run the following command in our Rails application root directory:
    This will create migration files in the db/migrate directory. 2. Now, we'll run the migrations:

The above migrations will create two tables named active_storage_blobs and active_storage_attachments. The active_storage_blobs table stores metadata about each uploaded file, such as its filename, content type, and size. The active_storage_attachments table is used to create associations between uploaded files and other records in the application, such as a user's profile picture or a product's image gallery.

  • Setting up cloud storage service: Now that we have installed Rails Active Storage and created the necessary tables, we can configure it to use a cloud storage service for production. In this case, we will use Amazon S3 as an example.
    1. We need to install the AWS gem by dropping this into the Gemfile:
      Then run bundle install:
    2. To set up Amazon S3 as our cloud storage service, we first need to create an S3 bucket and obtain an access key and a secret key from the AWS console. Once we have these credentials, we can add them to our Rails application as environment variables. We can get these keys by going to "My Security Credentials" in the console and generating a new access key file. key file
    3. Then, we can create a .env file in our Rails application's root directory and add the following lines to it:
      Note that AWS_REGION is the region where our S3 bucket is located, and AWS_BUCKET is the name of our S3 bucket.
    4. Next, we need to configure rails active storage to use Amazon S3 as our cloud storage service. To do this, we can add the following lines to our config/storage.yml file:
      This configures Rails Active Storage to use the Amazon S3 service with the credentials we added to our .env file. Now, when we deploy our Rails application to a Heroku server, the uploaded images will be saved to our Amazon S3 bucket.
    5. To use a cloud storage service like Amazon S3 in the production environment, we need to add a line to our config/environments/production.rb file.
      This line tells rails active storage to use the :amazon service we defined in our config/storage.yml file for storage in the production environment. Similarly, we can verify other environments like development.rb, and test.rb and add :local, and :test in the config.active_storage.service field.
    6. Finally, we need to make sure that the necessary environment variables are set in the production environment. We can do this by adding the following lines to our config/application.rb file:

How to Attach Files to Records

In Rails Active Storage, attaching files to records is a simple process that allows us to associate uploaded files with a specific record in our application.

  1. Set up the association: First, we need to set up the association between the file and the record. We can do this by adding the following line to the Record model:

    This creates an association between the model and the uploaded file. In this example, we're using has_one_attached to associate the file attribute with the model.

  2. Add file upload field: Next, we need to add a file upload field to the form for creating or updating the record. We can do this by using the file_field helper method:

    This will create a file upload field that is associated with the file attribute of the model in the UI.

  3. Handle file upload in the controller: When the form is submitted, we need to handle the file upload in the relevant controller action. We can do this by using the attach method on the model's file attribute:

    This code creates a new instance of the model, attaches the uploaded file to the file attribute, and then saves the record.

  4. Display the file: Finally, we can display the file in our views using the url_for method:

    This code creates an HTML img tag with the URL of the uploaded file.

How to Remove Files

To remove a file that's attached to a record using Rails Active Storage, we can use the purge method. For example, if we have a @record object with an attached file, we can remove the file like this:

This will remove the file from the storage service and delete its metadata from the active_storage_blobs and active_storage_attachments tables.

If we want to remove all the files attached to a record, we can use the purge_later method instead. This will enqueue a background job to perform the removal.

Serving Files Using Rails Active Record

There are two ways of serving files in Rails Active Record:

  • Redirect mode: When a user requests a file, the server responds with a redirect to the blob URL. The client then requests the file from the storage service. This means that the file is served directly from the storage service to the client.

    1. Retrieve the active storage attachment object that corresponds to the file we want to serve. For example, if we have a Record object with an attached file:
    2. Then we can use the url_for method to generate the blob URL for the attachment. This URL can be used to redirect to the file:
  • Proxy mode: The server acts as a proxy for the client, requesting the file from the storage service on the client's behalf and serving it to the client. This means that the server acts as an intermediary between the client and the storage service.

    1. In our routes file, add the following route for the rails storage proxy:

      This route maps the /rails/active_storage/* request to the show action of the ActiveStorage::RepresentationsController controller.

    2. To serve a file in proxy mode, we can use the rails_storage_proxy_path method to generate a URL that will proxy the file data through our application. For example:

    3. We can then use the generated URL to serve the file using an img tag or other HTML element:

Note:

  1. Proxy mode is slower than redirect mode since it requires the rails application to download and proxy the file data. However, it can be useful in situations where you need to add image processing transformations or other custom logic before serving the file.
  2. A proxy server is a server application that acts as an intermediary between a client requesting a resource and the server providing that resource.

Downloading and Analyzing Files

  • To download a file, we can use the following code in our view:

    This will generate a link to download the file stored in the @record.file attribute of the Record model.

  • To analyze an image file, we can use the ActiveStorage::Analyzer class provided by rails active storage. For example, to get the width and height of an image file:

  • To analyze a video file, we can use the ActiveStorage::Analyzer::VideoAnalyzer class. For example, to get the duration of a video file, we can use the following code:

Displaying Images, Videos, and PDFs

  • Displaying images: In our view, we can use the image_tag helper to display the image:

    We can also specify the size of the image:

  • Displaying videos: In our view, we can use the video_tag helper to display the video:

    We can also specify the size of the video:

  • Displaying PDFs: In our view, we can use the link_to helper to create a link to the PDF file:

    We can also embed the PDF file directly in the page using the iframe tag:

    This will embed the PDF file with a width of 100% and a height of 500 pixels.

Direct Uploading

Direct uploading is a technique that enables files to be uploaded from the user's browser directly to the storage service without going through the application server. Here's how it works:

  1. The client application layer requests a signed key from the backend (application server), which is essential to upload a file directly to the storage service.
  2. The backend uses its secret credentials (S3 bucket secret keys and access keys) to generate a signed key, which is only valid for a file with the same size and checksum. It then sends the signed key to the client.
  3. Now, the client (frontend) send a request to the storage service (like amazon aws s3) with the file and the signed key. The storage service checks the keys with the file and saves it if they match.
  4. The storage service responds to the client's request with a unique signed ID that can be used to identify the uploaded file.

The JavaScript file for direct uploading typically contains the client-side code for generating signed URLs or signed form fields to upload files directly to the storage backend. Let's take a simple example for AWS S3 storage service:

This file should be stored in the app/assets/javascripts/ directory. It can be included in a view using the javascript_include_tag helper:

This JavaScript code runs in the user's browser when the DOM is fully loaded. It listens for the click event on a form submit button, retrieves a signed URL for the file from the Rails backend, appends the file and signed URL to a FormData object, and sends an HTTP POST request to the storage backend to upload the file directly.

Testing

  • Add the following to the rails_helper.rb file:

    This will load the active storage fixture set, which provides an easy way to test the application's behavior with files.

  • Now, We use the fixture_file_upload method to create an instance of ActionDispatch::Http::UploadedFile that represents the file to be uploaded. For example:

    We are using a fixture file called example.jpg located in the spec/fixtures/files/ directory. We then use the instance of the file in our test request.

  • To test file downloads, we can use the ActiveStorage::Blob#service_url method to generate a URL that can be used to download a file. For example:

    Here, we are creating a Blob instance and using its signed_id attribute to generate a URL that can be used to download the file. We then use this URL in our test request.

FAQs

Q. How to change the default storage service in Rails Active Storage?
A. We can change the default storage service in the config/storage.yml file. Simply change the service key to the desired storage service.

Q. How to delete files from the storage service using Rails Active Storage?
A. We can delete files using the purge method on the attachment object. For example, if you have an attachment called avatar, you can delete the file using @user.avatar.purge.

Q. What types of files can be stored using Rails Active Storage?
A. Rails Active Storage supports storing any type of file, including images, videos, audio, and documents.

Conclusion

  • Rails Active Storage is a framework for handling file uploads and storage in Ruby on Rails applications. It supports multiple storage services like Amazon S3, Google Cloud Storage, and Microsoft Azure.
  • When displaying images, videos, or PDFs, rails active storage provides helper methods like image_tag, video_tag, and link_to for generating HTML tags.
  • We can easily attach files to records using has_one_attached or has_many_attached associations.
  • Removing files is also simple using the purge or purge_later method.
  • For serving files in rails active storage, we have two methods namely redirect mode and proxy mode.
  • Direct Upload is a feature of rails active storage that allows uploading files directly from the client to the storage service, bypassing the application server.
  • Rails active storage provides test helpers to simulate file uploads. We can use the fixture_file_upload method to create a file upload simulation for testing.