Active Storage - resizing images on upload
Our fix for app timeouts due to upload of large images when Active Storage was used
We’ve recently started a new project which has image upload and viewing as one of the core features. Keen to use the most up to date features of Rails, we used Rails 6 from beta and Active Storage for file upload. On previous Rails projects we had used a combination of Carrierwave and TinyPNG.
We found that we were starting to run into issues with memory on our app. We tried throwing more resource at it by upping our dyno on Heroku but this was a short term fix. We use a combination of Papertrail and Scout to track issues and noted our app was starting to experience timeouts.
We seen that the timeouts seemed to be happening when our application users were uploading very large images (over 7 megabytes) so decided that we needed to resize the images on upload. Papertrail and Scout made these issues extremely quick to spot, therefore allowing us to not waste time searching through logs on Heroku.
What appeared to be happening was the file would upload okay, but when the user was taken to the show view we were immediately requesting a variant be made, at the same time people hitting the homepage or index page for our controller were also requesting variants.
We ended up using MiniMagick to resize images. It is a dependency of the
image_processing gem which we were already using in the project, so there was no need for us to install it. If you are not using the
image_processing gem you may need to install MiniMagick.
So let’s say our app allowed users to upload images of cats, this is how we handled doing the resizing of images on the create action.
class CatsController < ApplicationController require 'mini_magick' def create @cat = current_user.cats.new(cat_params) params[:cat][:images].each do |image| mini_image = MiniMagick::Image.new(image.tempfile.path) mini_image.resize '1200x1200' end if @cat.save ... end end
We found that images processed this way that started out at over 7 megabytes, ended up at 143 kilobytes, with no loss to visible quality of the image. This should stop the request timeouts we were suffering and more importantly lead to a better experience for our users.