Image Uploads Cheatsheet

The CarrierWave and Cloudinary gems provide us with an easy way to allow image uploads through forms.


In your Gemfile, include

gem "carrierwave"
gem "cloudinary"

and then run bundle install in the Terminal.

In the file config/environment.rb, add this line to the end:

require "carrierwave/orm/activerecord"

Getting started with Carrierwave

Add a column to store the file’s URL

You need to have a column of type String in whichever table that you want to attach a file upload to. This column will, ultimately, store the URL of the uploaded file after CarrierWave hosts it.

If you already included the column when you generated your resource, great. Skip to the next step.

If not, you have to add it. For example, here we add a column called avatar to the users table, which we plan to store an image in:

rails generate migration add_avatar_to_users avatar:string
rails db:migrate

In your case, it may be song, transcript, image, etc.

Generate an uploader

From the command line:

rails generate uploader Avatar

In your case, change Avatar to match whatever you are trying to upload / the column you added to the table: Song, Transcript, Image, etc.

Restart your bin/server.

Mount the uploader in the model

In the relevant model add mount_uploader :avatar, AvatarUploader.

# app/models/user.rb
class User < ApplicationRecord
  mount_uploader :avatar, AvatarUploader

Again, customize to match your use case. :avatar should be the column you created, and AvatarUploader should be whatever uploader you generated.

Enhance the form

We need an <input type="file"> in our form to handle the upload. If you already have a type="text" input, change it; or if you don’t, add a new one:

<input type="file" id="avatar" name="avatar" class="form-control">

We also need to change the <form> tag itself to allow files to be uploaded by adding the enctype="multipart/form-data" attribute:

<form action="/create_user" method="post" class="form-horizontal" enctype="multipart/form-data">

Assign the file just like any other params

In your create/update actions, assign the new file upload just like any other form parameter:

@user.avatar = params.fetch(:avatar)

That should be it!

Retrieving the upload

CarrierWave will, by default, process the upload and then store it in your public folder, so that you can use it just like any other URL on the internet.

For example, we could now do

<img src="<%= user.avatar %>" class="img-responsive">

Adding Cloudinary for storage

CarrierWave works fine locally at this point, but it’s going to break if you try to host your project live on Heroku. That’s because Heroku won’t let you permanently write to the public folder of a live application.

If you’re going to deploy your app to Heroku, then you’ll need to find a file hosting service, like Amazon AWS S3, to store any uploaded files. Fortunately, there’s a great service called Cloudinary that makes it easy to host uploaded images; and they have a generous free tier.

Update your ImageUploader

To integrate Cloudinary, first adjust your ImageUploader file so it looks like:

class ImageUploader < CarrierWave::Uploader::Base
  include Cloudinary::CarrierWave

Most importantly, make sure you remove the line that says:

storage :file

Configure Temporary Storage for CarrierWave

Create an initializer file called carrierwave.rb in config/initializers and add the following content:

CarrierWave.configure do |config|
  config.cache_storage = :file

Retrieve Cloudinary API info

Next, you’ll need to sign up for a Cloudinary account. and get your API info. You can find your cloud name by going to Settings and clicking the Account tab. You can find your API key and secret by going to Settings and clicking the Security tab.

Add Cloudinary API info in Environment Variables

For security, it’s best to store your keys in environment variables. Read more on the how and why this is important in the guide on storing your credientials securely.

After pushing to Heroku, you’ll need to manually add these environment variables (Heroku calls them “Config Vars”) in the Settings tab of your application.

Store Cloudinairy API info in an intializer

Finally, create an initializer file called cloudinary.rb in config/initializers and add the following content:

Cloudinary.config do |config|
  config.cloud_name = ENV["CLOUDINARY_CLOUD_NAME"]
  config.api_key = ENV["CLOUDINARY_API_KEY"]
  config.api_secret = ENV["CLOUDINARY_API_SECRET"]
  config.cdn_subdomain = true

Further Reading