Uploading images to Amazon S3

To upload images to the cloud we use paperclip gem. This post will demonstrate how to use scaffolding to create a new Rails app from scratch that uses the Paperclip plugin to upload and display an image file. Initially the images are uploaded to the public folders of the app and later the app is configured to upload images to amazon’s S3 storage service.

This app displays the list of users with their profile pictures, username and email_id.

Paperclip uses imagemagik, so in order to get paperclip to work we need to install imagemagik. This can be done using

brew install imagemagick
gem install rmagick

$ rails new paperclip_sample_app

Setup the database.yml file and create a new MySQL database to use with the sample app. Contents of config/databases.yml

production:
adapter: mysql2
encoding: utf8
database: paperclip_sample_app_development
reconnect: false
pool: 5
username: root
password: password
socket: /var/run/mysqld/mysqld.sock

development:
adapter: mysql2
encoding: utf8
database: paperclip_sample_app_development
reconnect: false
socket: /var/run/mysqld/mysqld.sock
pool: 5
username: root

$ cd paperclip-sample-app
$ rake db:create

Add the paperclip gem to the Gemfile

source ‘http://rubygems.org’

gem ‘rails’, ‘3.0.10’
gem ‘mysql’
gem ‘paperclip’

gem ‘ruby-debug’, :groups => [:development, :test]

Lets generate the user model.

$ rails g scaffold user name:string email:string

Now we need to generate the database columns necessary for Paperclip on the user model object

$ rails g paperclip user avatar
$ rake db:migrate

The paperclip generator creates the following columns in the users table, “avatar_file_name,” “avatar_content_type,” “avatar_file_size” and “avatar_updated_at”

Next we need to add a line to the user model to let it know that it has a file attachment called avatar.

app/models/user.rb

class User < ActiveRecord::Base
has_attached_file :avatar
end

 These are the views used in the app.

app/views/users/new.html.erb

<h1>New user</h1>

<% form_for(@user, :html => { :multipart => true }) do |f| %>
<%= f.error_messages %>

<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :avatar %><br />
<%= f.file_field :avatar %>
</p>
<p>
<%= f.submit ‘Create’ %>
</p>
<% end %>

<%= link_to ‘Back’, users_path %>

app/views/users/show.html.erb

<p>
<b>Name:</b>
<%=h @user.name %>
</p>

<p>
<b>Email:</b>
<%=h @user.email %>
</p>

<p>
<b>Avatar:</b>
<%= image_tag @user.avatar.url %>
</p>

<%= link_to ‘Edit’, edit_user_path(@user) %> |
<%= link_to ‘Back’, users_path %>

app/views/users/show.html.erb

<p>
<b>Name:</b>
<%=h @user.name %>
</p>

<p>
<b>Email:</b>
<%=h @user.email %>
</p>

<p>
<b>Avatar:</b>
<%= image_tag @user.avatar.url %>
</p>

<%= link_to ‘Edit’, edit_user_path(@user) %> |
<%= link_to ‘Back’, users_path %>

Paperclip gives us different options to configure the images sizes. If no options are given, paperclip uploads the actual image size. In order to upload avatars we need to make the following changes to the user model.

app/models/user.rb

class User < ActiveRecord::Base
has_attached_file :avatar,
:styles => {
:thumb => “75×75>”,
:small => “150×150>”
}
end

This app stores the images in the public/system folders.
To upload images to the cloud we need to create an S3 account. The S3 account can be created at http://aws.amazon.com/. You can use your amazon account credentials to log in.  Note your ‘access key id’ and ‘secret access key’. These can be found at https://aws-portal.amazon.com/gp/aws/securityCredentials#access_credentials.
Include the aws-s3 gem,  in the gem file.
Gemfile

gem ‘aws-s3’, :require => ‘aws/s3’
Open up the Rails console and establish a connection to our account. We then create a new ‘bucket’ where our files will be stored.
# Terminal
> bundle
> rails c
console > include AWS::S3
console > Base.establish_connection!(:access_key_id => ‘yoursecretid’, :secret_access_key => ‘yoursecretkey’)
console > Bucket.create(‘paperclip_sample_app’)
console > Service.buckets
=> [#<AWS::S3::Bucket:0x00000 @attributes={“name”=>”paperclip_sample_app“, “creation_date”=>2012-02-12 00:00:00 UTC}, @object_cache=[]>]
console > Base.disconnect
console > exit
Next we need to config the user model so that paperclip uploads to S3 rather than the public/system folders. Before that we should create a file called in the config folder to store the S3 credentials.
# config/amazon_s3.yml

access_key_id: ‘yoursecretid’
secret_access_key: ‘yoursecretkey’
bucket: ‘paperclip_sample_app
The following changes must be made to the user model.
class User < ActiveRecord::Base
has_attached_file :avatar,
:styles => {
:thumb => “75×75>”,
:small => “150×150>”
},
:storage => :s3,
:s3_credentials => “#{Rails.root}/config/amazon_s3.yml”,
:path => “/:style/:filename”
validates_attachment_size :avatar, :less_than => 1.megabyte
end

Now the images will be uploaded into the cloud. Using the aws console we can look at the images that we uploaded.