Back to Blog

Rails 7 adds the ability to use pre-defined variants

on October 19, 2021
This blog is part of our Rails 7 series.

Rails 5.2 introduced ActiveStorage which made it possible to easily upload files to a cloud storage service like Amazon S3, Google Cloud Storage, or Microsoft Azure Storage. It also helped in attaching the files to active record objects.

Using ActiveStorage and ImageMagick we can transform image uploads and extract metadata from files. For transforming image uploads we can use image_processing gem with ActiveStorage and create variants of an image.

Previously for creating image variants, we needed to use image_processing gem with ActiveStorage processor. The default processor for ActiveStorage is MiniMagick, but we can also use Vips.

However, Rails 7 has added the ability to use pre-defined variants which provides a way to easily create variants for images.

Let's assume we have a model Blog. Using has_one_attched every record can have one file attached to it.

1# app/models/blog.rb
2class Blog < ApplicationRecord
3  has_one_attached :display_picture # Setup mapping between record and file
4end

To create a blog with an attachment on display_picture.

1# app/views/blogs/new.html.erb
2<%= form.file_field :avatar %>
1# app/controllers/blogs_controller.rb
2class BlogsController < ApplicationController
3  def create
4    blog = Blog.create!(blog_params)
5    session[:user_id] = blog.id
6    redirect_to root_path
7  end
8
9  private
10    def blog_params
11      params.require(:blog).permit(:title, :display_picture)
12    end
13end

Before

If we want to create variants of display_picture, we needed add the image_processing gem to the Gemfile.

1# project_folder/Gemfile
2gem 'image_processing'

Then to create variants of the image, we can call the variant method on the attachment record.

1# app/views/blogs/show.html.erb
2<%= image_tag blog.display_picture.variant(resize_to_limit: [100, 100]) %>

Rails 7 onwards

We can use the variants option on has_one_attached.

1class Blog < ActiveRecord::Base
2  has_one_attached :display_picture, variants: {
3    thumb: { resize: "100x100" },
4    medium: { resize: "300x300" }
5  }
6end

To display we can use the variant method.

1# app/views/blogs/show.html.erb
2<%= image_tag blog.display_picture.variant(:thumb) %>

variants can also be used on has_many_attached. Check out this pull request for more details.