Getting vips to work with Rails on Heroku
As of Rails 7, vips is the default way to manipulate images. This is how we got vips working on Heroku
Suppose you’re starting a new project using Rails 7 and ActiveStorage to handle image uploads. In that case, one change you will notice is vips is the standard way we manipulate images now, replacing ImageMagick.
This was the first time we’ve used vips, and we spent a bit of time trying to work out why things weren’t working on Heroku. I will show you what we did to get things working.
What is vips?
First of all, you might be wondering what vips is. It is an image processing library, so a suite of tools we can use to change images (resize, change colour, etc.).
From the vips library README:
libvips is a demand-driven, horizontally threaded image processing library. Compared to similar libraries, libvips runs quickly and uses little memory.
The “uses little memory” bit is appealing to us Rails folk running things on web servers.
Getting it running locally
I won’t get into the ActiveStorage part of the setup, but from the Rails side, you will need the
image_processing gem installed; in a standard Rails install, the line in the Gemfile will look like;
gem 'image_processing', '~> 1.2'
If you don’t already have vips installed on your computer, you will need it.
On a Mac with homebrew, you can run
brew install vips, and everything should be good to go.
On a Linux machine with
apt, you can run
apt get libvips.
I’m not sure about Windows, but it seems like there are binaries you can get from the vips release section.
Getting it running locally is one thing, but we need to host it somewhere if other people want to use our application; for us, that somewhere is almost always Heroku.
Heroku has the notion of buildpacks; these are scripts that run to set up the server for you on each deployment. A Rails project would use the Ruby buildpack, which will install Ruby and many common dependencies that Ruby projects need.
At the time of writing, vips is not seen as a common enough dependency to include in the Ruby buildpack. Hopefully, that is something that can change. There is an open issue discussing this very point; it looks like maybe it will come with the newest Heroku stack, but let’s not hold our breath!
It and other threads talk about a buildpack called heroku-buildpack-vips. Unfortunately, we didn’t have much joy by using this buildpack alone. Some folk use it in combinations with some manual installs.
This is what we did, which appeared to work.
Use the apt buildpack; this buildpack allows you to specify which packages should be installed by Heroku; it uses an Aptfile which you can commit with your code.
In our first attempt, we just installed libvips, so our
Aptfile looked like this;
This appeared to work; we deployed our application, and ActiveStorage could save off images we were then manipulating.
libglib2.0-0 libglib2.0-dev libpoppler-glib8 libheif-dev libvips-dev libvips
I don’t know enough about this setup to comment, but I presume the above will cover more use cases.
Is there a better way?
Is there a better way than using the
Aptfile? I’d love to use a single buildpack, which seems more self-documenting than a file full of things to install.