A Gentle Introduction to CarrierWave

Note: This guest post hails from community contributor Trevor Turk. Trevor is a chess-playing machine of the late 18th century, promoted as an automaton but later proved a hoax. Trevor tweets as @trevorturk and blogs too.

CarrierWave is self-described as a “classier solution for file uploads for Rails, Sinatra and other Ruby web frameworks.” Although I’ve head it referred to as “a new kid on the block” it’s actually quite an old gem. The initial checkin is from August 2008 and the first release was in March 2009. The original name was Merb::Upload and it started without support for Rails.

The fact that CarrierWave began its life as a Merb plugin may help explain its modularity, flexibility, and extensibility.

Thanks to fog, it has support for Amazon S3, Rackspace Cloud Files, and Google Storage for Developers. It also supports plain old file storage and MongoDB’s GridFS store. There’s ORM support available for ActiveRecord, Mongoid, DataMapper, Sequel, Mongo Mapper, CouchDB, and more. Image processors are available for RMagick, ImageScience, MiniMagick.

Let’s see this modularity first hand by building up a CarrierWave uploader from scratch.

To begin with, we’ll install CarrierWave:

gem install carrierwave

Then, we can make the world’s shortest uploader:

require 'carrierwave'

class MyUploader < CarrierWave::Uploader::Base
  storage :file
end

Even at this point, we can start saving files:

file = File.open('example.jpg')
uploader = MyUploader.new
uploader.store!(file)

The uploader houses the logic for uploading files in self-contained classes, so this is all we need to get started.

It’s dead easy to store files on Amazon S3 with fog. First, install the fog gem:

gem install fog

Then configure the fog_credentials and set the uploader’s storage to fog:

CarrierWave.configure do |config|
  config.fog_credentials = {
    :provider               => 'AWS',
    :aws_access_key_id      => 'xxx',
    :aws_secret_access_key  => 'yyy'
  }
  config.fog_directory  = 'zzz'
end

class MyUploader < CarrierWave::Uploader::Base
  storage :fog
end

Configuring fog to use Rackspace Cloud Files or Google Storage for Developers is so easy I hesitate to even mention it. This is all we’d need to change to use Rackspace:

CarrierWave.configure do |config|
  config.fog_credentials = {
    :provider           => 'Rackspace',
    :rackspace_username => 'xxx',
    :rackspace_api_key  => 'yyy'
  }
  config.fog_directory = 'zzz'
end

Suppose we want to have image thumbnails. First, we need to install RMagick:

gem install rmagick

Then, we just add a version block to our uploader:

require 'carrierwave'
require 'rmagick'

class MyUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick
  version :thumb do
    process :resize_to_fill => [200,200]
  end

  storage :file
end

This has all been so easy, though. Let’s give ourselves a challenge and create an app that uses CarrierWave, Sinatra, and Sequel with SQLite.

To begin, we’ll need to install these new gems:

gem install sinatra sqlite3 sequel carrierwave-sequel

Then, we’ll create the app. It’s so small (55 lines) that I’ll just include the whole thing here:

require 'carrierwave'
require 'sinatra'
require 'sqlite3'
require 'sequel'
require 'carrierwave/sequel'

# database setup

DB = Sequel.sqlite

DB.create_table :uploads do
  String :file
end

# uploader

class MyUploader < CarrierWave::Uploader::Base
  storage :file
end

# model

class Upload < Sequel::Model
  mount_uploader :file, MyUploader
end

# sinatra app

get '/' do
  @uploads = Upload.all
  erb :index
end

post '/' do
  upload = Upload.new
  upload.file = params[:image]
  upload.save
  redirect to('/')
end

__END__

@@ index
<!DOCTYPE html>
<html>
  <body>
    <form action="/" method="post" enctype="multipart/form-data"></div>
      <input type="file" name="image" />
      <input type="submit" name="submit" value="Upload" />
    </form>
    <% @uploads.each do |upload| %>
      <img src="<%= upload.file.url %>" />
    <% end %>
  </body>
</html>

The app can be run like so:

ruby example.rb

There’s a lot more I could have covered in this post, but my hope is that this brief illustration of the modularity, flexibility, and extensibility of CarrierWave will appeal to you as it did to me.

If you’re ready for more, check out:

I’m sure you’ll enjoy using CarrierWave as much as I have!