Saving files in Amazon S3 using Carrierwave and Fog Gem

on

Long long time ago in a far far away land….. I am just kidding. So I needed a gem to do file uploads(in my case images but you can upload anything) and I was looking at various options. Paperclip is a popular option but there is a new kid on the block (so i read in various forums)… Carrierwave.

Now I have not used Paperclip but what I read was that Carrierwave is more flexible and powerful than Paperclip so if are interested then keep reading. Now let me tell you that you may need to do some additional settings, I will not get into details because the wiki page of Carrierwave is pretty intensive. The purpose of writing this post is to highlight a couple of issue that I ran into and some settings which were not explained.

Step 1: Install the Carrierwave gem

  gem install carrierwave

Step 2: Update the gem file

gem carrierwave

Step 3: Now you need a uploader. This is the file which has all the settings like which folder the image will be saved, setting the image quality, caching etc. I wanted to call my uploader class as ImageUploader

rails generate uploader ImageUploader

Step 4: Install fog gem

gem install fog

Step 5: Update gem file

gem ‘fog’, ‘~> 1.3.1’

bundle install

Step 6: Choose the storage type

class ImageUploader < CarrierWave::Uploader::Base

     storage :fog

end

Step 7: Create model. Mine was called Photo so I create photo.rb. Notice the line number 10.

class Photo < ActiveRecord::Base

#Attributes or fileds
attr_accessible :image,:pic_name,:description,:albums_id

#associations
belongs_to :albums

#carrier wave
mount_uploader :image,ImageUploader

#Validations
validates :description,:pic_name,:albums_id, :presence=>true
validates_uniqueness_of :pic_name
end

Step 7: How to upload file and show uploaded file in the html page

Upload page:

<%= form_for @user, :html => {:multipart => true} do |f| %>
  <p>
    <label>My Avatar</label>
    <%= f.file_field :avatar %>
    <%= f.hidden_field :avatar_cache %>
  </p>
<% end %>

View uploaded image

<%= form_for @user, :html => {:multipart => true} do |f| %>
  <p>
    <label>My Avatar</label>
    <%= image_tag(@user.avatar_url) if @user.avatar? %>
    <%= f.file_field :avatar %>
    <%= f.hidden_field :avatar_cache %>
  </p>
<% end %>

Step 8: Now comes the most important part. Setting up fog. Now if you follow the documentation on  Carrierwave then you will run into issue(I will explain the issue and fix below). The wiki page said create a file fog.rb in the lib/carrierwave/storage/fog.rb and that’s what I did. I created the file with the contents below.

CarrierWave.configure do |config|
  config.fog_credentials = {
    :provider               => 'AWS',       # required
    :aws_access_key_id      => 'xxx',       # required
    :aws_secret_access_key  => 'yyy',       # required
    :region                 => 'eu-west-1'  # optional, defaults to 'us-east-1'
  }
  config.fog_directory  = 'name_of_directory'                     # required
  config.fog_host       = 'https://assets.example.com'            # optional, defaults to nil
  config.fog_public     = false                                   # optional, defaults to true
  config.fog_attributes = {'Cache-Control'=>'max-age=315576000'}  # optional, defaults to {}
end

Now before you start you need to have a S3 account on Amazon S3. So get your Amazon access key and secret access key. For example mine was …. hehehe no I am not going to share my access keys with you :-). Anyway if you forgot to note down your access key and incase you are wondering where I can find that and are guessing that it will be on S3 Dashboard then you are mistaken just like me. You can find that on your account settings –> Security credentials.

So after you have noted down your key and access key. Go ahead create a bucket on S3. A bucket is nothing but a directory. It’s just a fancy shimancy name for directory that Amazon came up with. You can further create sub directories.

Now coming back to the meaty part and fog.rb file. I updated the below fields in the fog.rb

:aws_access_key_id      => 'xxx',       # required
    :aws_secret_access_key  => 'yyy',       # required

I commented out the below lines as they are optional

#:region                 => ‘eu-west-1’  # optional, defaults to ‘us-east-1’

I was not sure what was my region so if you are not sure as well then go ahead and comment it.

#config.fog_host = ‘https://s3.amazonaws.com’ # optional, defaults to nil
#config.fog_public = true # optional, defaults to true

If you leave config.fog_host to https://s3.amazonaws.com then I ran into issues which said –

“LoadError (Expected /Users/dinesharora/Desktop/Mydocument/ruby-proj/album/app/uploaders/image_uploader.rb to define ImageUploader):”

So I commented that field. 

The next part that I was not sure about was how to tell fog which folder or directory I want to upload my files. I had created a bucket(directory) called myalbums and had created a sub folder called devlopment.

So I updated

config.fog_directory  = ‘myalbums/development‘, which did not work. The right way to do is

config.fog_directory  = ‘myalbums’ and also in ImageUploader  update the line

def store_dir
“development/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}”
end

That’s it. Now just start the server and start uploading, that’s what the forums said but as it always happens with me(nothing works for me the first time) I ran into error(as I mentioned earlier that you will if you create the fog.rb in lib/carrierwave/storage/ folder) which said –

ActionController::RoutingError (uninitialized constant CarrierWave::Storage::Fog):
app/uploaders/image_uploader.rb:11:in `<class:ImageUploader>’
app/uploaders/image_uploader.rb:3:in `<top (required)>’
app/models/photo.rb:10:in `<class:Photo>’
app/models/photo.rb:1:in `<top (required)>’
app/controllers/photo_controller.rb:1:in `<top (required)>’

To get rid of this error, just copy the file in config/initializers and now I could finally say – That’s it!!!! 🙂

~~~ Cheers!

  • Atsuki

    I would like to say thanks!

  • Hey, I’m still getting a 403 error.
    However this made setting up this gem much clearer.

    Thanks

  • Most helpful…worked first time through

  • Raghunandan

    First of all thank you so much.

    I wanted to check that in my website. My android app is sending media to rails server on aws. How can I do that using curl request. Please help