When I first looked into adding images to my Rails applications, I thought I had one problem I needed to solve. After doing a bit of research, I started to realize I actually had three problems I needed to solve:
- how to upload an image
- how to resize an image
- how to store an image
I haven’t found a gem that lets you do all of these things in one shot. After a bit of research and trail and error, here are the two main options I found:
Option 1: Carrierwave + MiniMagick + ImageMagick + Fog + S3
This involves a lot of moving parts. Let’s break it down:
- CarrierWave is a file uploader for Rack based applications. You can install this as a gem.
- MiniMagick is a Ruby wrapper for a command line application called ImageMagick, which lets you manipulate images. You need to first install ImageMagick locally using
brew install imagemagickand then you can install MiniMagick as a gem.
- Amazon’s S3 is a popular and robust choice for storing files such as images. In order to play nicely with Amazon cloud services there’s a gem you can use called Fog that helps you navigate the “fog”.
I tried this approach, and it was all fine and dandy until I got to S3. I couldn’t quite escape the fog. I ended up with a cryptic config error and spent another 30 min staring at Amazon’s admin panel trying to figure out which key(s) it didn’t like. For my lightweight app that just wanted to store simple images, it was a lot of work to get going. I starting looking around for a simpler alternative.
Option 2: Carrierwave + Cloudinary
I’m so happy I found this pair! Cloudinary handles both image manipulation and cloud storage for you. And as a bonus, it comes as a Heroku addon! It took 5 min to setup and worked like a charm.
The only downside to this adventure with image uploaders is that I didn’t find a great tutorial out there for tying everything together. Once you find the tools, it’s not really clear how you integrate it with your existing models and views. Here’s my attempt at that:
Using Carrierwave and Cloudinary
We are going to add a profile picture to a user. Here is an overview of what we want to accomplish:
Step 1: Add Carrierwave and Cloudinary to your Gemfile
Step 2: Add Cloudinary to Heroku
Step 3: Add a Cloudinary config to your app
If you go to
$ heroku config you should now see a Cloudinary URL. Create a config file called
config/initializers/cloudinary.rb and store the URL in
config/application.yml if you’re using Figaro to handle your environmental variables.
Remember to update your environment variables in Heroku,
$ figaro heroku:set -e production.
Step 4: Create an image uploader
Carrierwave has an generator we can use to create an uploader tool. This uploader provides config options and methods to upload and display our images. Let’s call it Avatar. Each of our users will have an avator associated with them, so we will need to add an avator attribute to the users table.
Step 5: Modify the User model
CarrierWave provides a method called
mount_uploader which gives a model attribute additional functionality to assist in uploading. Add the following to
The second parameter
AvatarUploader tells it which file to use for uploading.
Step 6: Modify the User controller
We added a new
avatar attribute to our User model. Now we need to allow the attribute to be updated in our controller. Change your params to the following:
Step 7: Modify the uploader
Our uploader processes and resizes the images. We want to add/uncomment the following:
Step 8: Modify the views
You can do this many different ways. Here’s one example. I’m calling methods provided by
avatar_uploader.rb on my User object to generate a profile picture. Here is a submit form:
Notice that the above method
image_tag() is being used to display the current profile picture.
Step 9: Cleanup
Putting it all together: here is a commit from an app of mine that covers this process from start to finish.