Use carrierwave to upload files to s3

JiaHung Lin
Sep 3, 2017 · 4 min read

Sometimes we need to upload files to server, we can use the “carrierwave” gem to help us. We choose the s3 as our server and we will deploy the app to heroku.

If you want to try it yourself, you can just reference the following 2 resources and skip the rest of the article.

  • You can check the doc of carrierwave first for detail information.
  • For uploading to s3, you can check this video from railscast.

Set AWS S3 account

You can check this video tutorial for detail process.


Install “imagemagick”

$ brew install imagemagick

The reason we can’t install it by gem install command is because imagemagick is written by C, not Ruby.

If you want to use imagemagick, you had better install it before installing carrierwave and mini_magick to prevent some errors.

gem 'carrierwave'
gem 'mini_magick'
gem 'fog-aws'

The gem will help us to upload file to s3.


This article will show you how to create a new video, which includes the small cover image and large cover image. We will upload the files to s3 via carrierwave gem.

Set tables

Create the essential columns for video

def change
create_table :videos do |t|
t.string :title
t.text :description
t.integer :category_id
t.string :small_cover # small cover of video
t.string :large_cover # large cover of video
t.string :video_url

Create uploader

$ rails generate uploader large_cover
$ rails generate uploader small_cover

Edit the uploader files


class LargeCoverUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
process :resize_to_fill => [665, 375] # the defualt image size# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir


# app/uploaders/small_cover_uploader.rb
class SmallCoverUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
process :resize_to_fill => [166, 236] # the defualt image size# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir

Mount the uploader

Mount the uploader in video.rb


class Video < ActiveRecord::Base
mount_uploader :small_cover, SmallCoverUploader
mount_uploader :large_cover, LargeCoverUploader

Upload to s3

You can reference the code in Using Amazon S3 section.

Then we need to edit the carrierwave.rb.


CarrierWave.configure do |config|
if Rails.env.staging? || Rails.env.production?
config.fog_provider = ‘fog/aws’
config.fog_credentials = {
:provider => ‘AWS’,
:aws_access_key_id => ENV[‘AWS_ACCESS_KEY_ID’],
:aws_secret_access_key => ENV[‘AWS_SECRET_ACCESS_KEY’],
:region => ‘ap-northeast-1’ # Tokyo
config.fog_directory = ENV[‘S3_BUCKET_NAME’] = :fog
else = :file
config.enable_processing = Rails.env.development?

Since we want to deploy our code to heroku, you need some ways to set your api key. While setting some sensitive data like api key, we need some safer way to store it, instead of hardcore the data then make it public. The better way to store the informaiton is thorugh environment variable.

You can check this page for more detail.

In this post we will set the environment variable directly on heroku.

In your console, type

$ heroku config:set AWS_ACCESS_KEY_ID=sdfafgjioas
$ heroku config:set AWS_SECRET_ACCESS_KEY_ID=sdfafgjioasjdogijaas
$ heroku config:set S3_BUCKET_NAME=your_bucket_name

Or you You can also edit config vars on your app’s settings tab on Dashboard.

Go to dashboard => your app => setting => click “Reveal Config Vars”

Then you can set the Config vars.

Check this article for more information.

Set route

resources :videos, only: [:new, :create]

Create view

The view will look like.

Basically we won’t upload video directly to s3, since it will take too much space and cost a lots. You can use service like Youtube, Vimeo or Wista.

The view template


= bootstrap_form_for [:admin, @video], layout: :horizontal, label_col: “col-sm-3”, control_col: “col-sm-6”, html: {class: “form-horizontal”} do |f|
%a(href=”/ui/admin_views_payments”) Recent Payments
%a(href=””) Add a New Video
= f.text_field :title, control_col: “col-sm-3”
= :category_id, options_for_select( {|category| [,]})
= f.text_area :description, rows: 8
= f.file_field :large_cover, class: “btn btn-file”
= f.file_field :small_cover, class: “btn btn-file”
= f.text_field :video_url, label: “Video URL”
%input(type=”submit” value=”Add Video” class=”btn btn-default”)

Set controller

class Admin::VideosController < ApplicaitonController
def new
@video =

def create
@video =

flash[:success] = “You have created the #{video.title}”
redirect_to new_video_path
flash[:error] = “Please check the error, something wrong with your input.”
render :new


def video_params

1.Create a fog.rb file under lib directory

touch lib/fog.rb

2.Add following content in the file

module Fog
# no content

3.Edit config/initializers/carrier_wave.rb:

require ‘carrierwave/storage/abstract’
require ‘carrierwave/storage/file’
require ‘carrierwave/storage/fog’
CarrierWave.configure do |config|
# code emitted

Check evadne’s answer in this article.