Ruby on Rails greatly influenced web app development through innovative features such as seamless database table creation, migrations, and scaffolding of views to enable rapid application development. Many web frameworks Django(Python), Laravel(PHP), Phoenix (Elixir) and Sails.js(Node.js) borrowed the concepts of Rails framework.
Ruby on Rails is strongly associated with startups and is flexible and well supported by open source community. The Ruby on Rails 5.2 version included many features and some of the highlights are mentioned below
- Active Storage
- Redis Cache Store
- HTTP/2 Early Hints
- Content Security Policy
The below points will serve as an introduction to the new Active Storage API of the Rails 5.2 release.
Existing File upload gems in Rails
There are many file attachment libraries for RoR that makes file uploading a lot easier. Some of the popular libraries are paperclip, carrier wave. Additional configurations allow these gems to handle uploads to various cloud services like amazon s3. For example, paperclip can be configured to use ‘AWS-SDK-S3’ to support uploads to Aws S3 storage.
ActiveStorage and advantages over other solutions
Rails 5.2 introduced ActiveStorage library. It’s a built-in way to deal with uploads without extra dependencies like Paperclip, Carrierwave or Shrine. ActiveStorage facilitates uploading files to a cloud storage service like Amazon S3, Google Cloud Storage or Microsoft Azure Storage and attaching those files to Active Record objects. It also supports with a local disk-based service for development and testing purposes.
According to David Heinemeier Hansson, ActiveStorage was extracted from Basecamp 3. The project was initiated in mid-2017 and is now merged into Rails core. Let’s see the advantages of ActiveStorage compared to other similar solutions.
No external dependencies:
As we know that ActiveStorage code is merged into Rails, there is no need to install/setup external dependencies. All features are built in and so require less effort for maintenance. Being the default library is the main advantage.
No need for migrations:
Gems like paperclip do not provide table structure by default and the developer needs to create database fields and migrations in order to use the gems. ActiveStorage by default provides all that is required to store file information.
ActiveStorage provides a common config layer and abstracts the configuration for various third-party storage services. It’s easy to switch and manage various cloud storage services.
Image post-processing and previews:
ActiveStorage, by default support MiniMagick (Ruby implementation of famous ImageMagick) and makes it easy to create resized variants of the original uploaded images. Also its easy to create previews of the uploaded files without completely downloading them. ActiveStorage can be integrated with external tools like MuTool and FFmpeg to achieve this.
Let’s create a basic example to understand how to use ActiveStorage to upload files to the local disk but before that let’s see how to set up this library in a brand new Rails 5.2 application.
As we know, Rails 5.2 ships with ActiveStorage but it’s not enabled by default. To enable it, run the below command in the project directory.
The above command generates migrations for two tables – active_storage_blobs and active_storage_attachments. These tables are required for storing data related to the uploaded files. Run the command ‘bundle exec rails db:migrate’ to create the tables.
A config file ‘config/storage.yml’ is also generated, For each service your application uses, provide a name and the requisite configuration. The example below declares three services named local, test, and Amazon:
root: <%= Rails.root.join(“storage”) %>
root: <%= Rails.root.join(“tmp/storage”) %>
The last step in configuring ActiveStorage is to set up the config ‘Rails.application.config.active_storage.service’. To use local config for ActiveStorage you would add the following to config/environments/development.rb:
config.active_storage.service = :local
That’s enough configuration, let’s jump to next section and start creating a basic rails app.
A basic example using active storage to local disk
In this section, we will create a basic rails app that allows the users to create his profile along with an image. We will be using local disk storage in this example for which the setup we have already discussed in the previous section. To avoid spending time on build crud, let’s focus on the ActiveStorage part and leave the rest to Rails scaffolding feature to generate controller and views
Assuming you have already created a Rails 5.2 application and configured ActiveStorage, let’s scaffold a profile model
rails g scaffold profile name city
The above command will generate necessary models, controllers, and views required for crud operations. Let’s add an image to the profile. Open models/profile.rb and the following line to the model definition
class Profile < ApplicationRecord
In the Profile controller, permit the :image attribute.
params.require(:profile).permit(:name, :city, :image)
Now, update the create profile form, to enable the user to upload image. Open ‘_form.html.erb’ and the add the following code.
<%= form.label :image %>
<%= form.file_field :image %>
<%= form.submit %>
<% end %>
Finally, to display the uploaded image, update the show.html.erb to render the image as shown below.
<%= image_tag @profile.image %>
<%= link_to ‘Edit’, edit_profile_path(@profile) %> |
<%= link_to ‘Back’, profiles_path %>
That’s all we need to do to add image upload feature using ActiveStorage. The example can be downloaded at ‘https://github.com/SigmaDev1/activestorage_example’
Updating example to enable cloud storage
Let’s update our example to use Amazon s3 cloud storage.
The first step is to add declare S3 service in config/storage.yml:
Add gem “AWS-SDK-s3” to the gemfile and bundle install
Finally, update “config.active_storage.service = :amazon” to use s3 for file storage.
ActiveStorage has many other advanced features like syncing files between different storage services using the mirroring feature. Also, we can extend ActiveStorage::Service to build custom storage providers.
- Example code : https://github.com/SigmaDev1/activestorage_example