Intro
Heroku is awesome, it makes deployment easy and is an all around great service. However, it does have a few limitations and one of those is the inability to upload files. When we need to do this, we use thoughtbot’s paperclip gem which makes managing file attachments easy coupled with Amazon’s S3 (simple storage service).
Amazon S3
S3, simply put, is cloud storage provided by Amazon. Although it does have a free tier there is a price associated with using S3. As of this writing, the free tier gives you 20,000 GET requests, 2,000 PUT requests and 15gb of data transfer out per month. You can view all of the pricing tiers and information at Amazon’s S3 Pricing Page. To get an estimate of your cost you can head over to Amazon’s cost estimator and clicking “Amazon S3″ on the left. To get started, you’ll need to sign up (note: all sign-ups require a credit card including the free tier). Once you’re in you’ll need to go to your security credentials page under “My Account / Console”:
Once you’re on the security credentials page, you’ll need to scroll down to the “Access Credentials” section and by default you should be on the “Access Keys” tab:
You need to make note of the Access Key ID and then click the “Show” link for your Secret Access Key. Copy these and hang on to them, we’ll need them in just a few minutes. Next we’ll need to create a “Bucket” which for our purposes is similar to a folder. There are several ways you can go about doing this. To create a bucket we’ll use the S3 AWS management console provided by Amazon. In the upper left corner you’ll see the “Create Bucket” button:
Click it. You’ll see a screen like this:
Name your bucket whatever you’d like and select the appropriate region. I’m going to use “US Standard” because… I’m in the US. Then hit the “Create” button. Congratulations, you just created your first bucket. Now let’s code.
Code
You should start by installing the paperclip and S3 gems (we need a gem to communicate back and forth with S3), in your gemfile:
gem 'paperclip' gem 'aws-s3'
Go ahead and bundle install
Next, much like you have a database.yml in your config folder, you need to create an s3.yml that the S3 gem will use to reference your S3 credentials. The contents of the file should look like this:
access_key_id: secret_access_key: bucket:
You should fill this out accordingly based on the information you got from the Security Credentials section of the S3 site and whatever you named your bucket. Update it and save.
Next, we need to update our model to include an attached file. For this tutorial, I’m going to attach an image to a model called User and I’m going to call it Avatar. So here’s what we need to do in the console:
rails generate migration add_avatar_to_users avatar_file_name:string avatar_content_type:string avatar_file_size:integer avatar_updated_at:datetime
Go ahead and run rake db:migrate. So we’re adding 4 properties to our user model: avatar_file_name, avatar_content_type, avatar_file_size, avatar_updated_at. All of these should be self explanatory in case it’s not clear, the content_type property will store information like jpeg, png, etc.
Let’s head over to the model (for me user.rb) and let it know of this new attachment:
has_attached_file :avatar,
:styles =>{
:thumb => "50x50",
:medium => "400x400"
},
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml"",
:path => ":attachment/:id/:style.:extension",
:bucket => "the_bucket_name"
On lines 2-5 we’re telling paperclip we want 2 styles of our uploaded image (you can change this to allow for more styles with different sizes). It’ll resize them for us an store 3 copies, the thumb, medium-sized, and the original uploaded image. Just to be clear, it WILL resize these images for us (using ImageMagick). On line 6 we’re identifying the fact that we’d like to use S3 to store this avatar and then on line 7 we define our configuration file’s location. On line 8 we are defining our directory structure for storage on S3. Let’s say you’re a user with the id of 5. If you upload your jpeg avatar, it’ll be stored inside the bucket we specified with the following path: avatar/5/medium.jpg. On line 9 we use the same bucket we created previously.
Now we need to update our views to handle the new avatar. We’ll start with our form to create users (or edit users):
<%= form_for :user, @user, :url => user_path, :html => { :multipart => true } do |form| %>
<%= form.file_field :avatar %>
<% end %>
This is pretty straightforward, just make sure you’re making the form multipart (to allow for the file upload) and then adding the file field for the avatar. To display this avatar you do the following:
<%= image_tag @user.avatar.url(:thumb) %>
You can, of course, change :thumb to be :medium or whatever style you’ve predefined in the model. For additional reference or to see the other cool things you can do with paperclip, head over here.

















