File Uploading in Rails with Paperclip and AWS

There are many instances in which you may want to give the users of your application the ability to upload images--maybe you're creating a blogging platform and users want to upload images for their profiles or their posts, maybe you're creating a social networking site and users want to share pics with each other.

A few gems make file uploading and hosting very manageable in rails.

What you'll need

Once you're app is up and running, add these gems to your Gemfile:

  • gem "paperclip", "~> 4.2"
  • gem 'aws-sdk', '< 2.0'

Make sure you are not using the most recent version of aws-sdk. It is not compatible with Paperclip.

You will also need to have the Image Magick Library installed. In the root of your computer, run brew install imagemagick

Then, in the command line, run which convert. This will give you the path to the Image Magick library. You need to tell Paperclip where the IM library lives. In the environments subdirectory of the config directory of your app, add the following line to production.rb and development.rb:

Paperclip.options[:command_path] = "/usr/local/bin/"

Setting up storage with AWS

If your users are going to upload images, you'll need a place to store them on the server side. If you're using a platform like Heroku, you may run in to trouble trying to store large or multiple images. Amazon Web Services makes it easy to store images in the cloud and connect that storage to your app.

  • Create and AWS account and log in to the management console
  • In the console, go to your 'security credentials' to get your api key and secret.
  • In the console, under 'storage and services' create a new S3 bucket. A bucket is like a directory in which to store your files remotely. Give the bucket a name that relates to your app to make it easier to manage in the future as you add additional buckets for other apps.
  • Lastly, attach a new security policy to your AWS user. If you haven't yet created a user in AWS:
    • Click your name on the top right of the screen and select "security credentials".
    • Then, on the sidebar on the left, click "Users".
    • Click on the user (not the checkbox next to the user) and then click the "permissions" tab on the view you are taken to.
    • Click "Attach Policy" and attach the "AdminstratorAccess" policy.

Configuring your app's environment

  • Add your S3 bucket name, AWS Access key and secret access key to your application.yml (if you're using the Figaro gem) or secrets.yml file. If you're using Heroku, you will need to configure these variables with the heroku command line tools

your application.yml:

S3_BUCKET_NAME: yourbucketname

AWS_ACCESS_KEY_ID: XXXXXXXXXXXXX 
AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXX

in the command line:

$ heroku config:set S3_BUCKET_NAME=yourbucketname AWS_ACCESS_KEY_ID=XXXXXXXXXXXXX AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX
  • Configure Paperclip with S3 in config/production.rb:
# config/production.rb

config.paperclip_defaults = {
  :storage => :s3,
  :s3_credentials => {
    :bucket => ENV['S3_BUCKET_NAME'],
    :access_key_id => ENV['AWS_ACCESS_KEY_ID'],
    :secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
  }

Adding image attachments to your model

Now, you need to create a migration to give the appropriate model the ability to have an image upload. Let's use the example of a blog post having an image uploaded to it.

rails g migration AddImageUploadToPost

Then, in your migration file:

class AddImageUploadToPost < ActiveRecord::Migration

def change
    add_attachment :posts, :image_upload
end 

In the Post model:

class Post < ActiveRecord::Base
   has_attached_file :image_upload
   validates_attachment_content_type :image_upload, 
   :content_type => /\Aimage\/.*\Z/
end

Uploading an image

Now, we need to give our users a form field that allows them to upload an image when they create a new post. In your form_for a new post, add the following form field:

<%= f.file_field :image_upload %>

When a user submits the form to create a new post, the parameters that you send to the create action of the posts controller will contain the necessary info about the file. Set post.image_upload equal to the params[:image_upload] and save the post.

Rendering an uploaded image in the view

We're almost done! When you are ready to render an post's image in the view, simply set the image source to post.image_upload.url. This points to the location of the image in your AWS bucket.

subscribe and never miss a post!

Blog Logo

Sophie DeBenedetto

comments powered by Disqus
comments powered by Disqus