Deep-dive on the Next Gen Platform. Join the Webinar!

Skip Navigation
Show nav
Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
Hide categories

Categories

  • Heroku Architecture
    • Compute (Dynos)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Developer Tools
    • Command Line
    • Heroku VS Code Extension
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery & Integration (Heroku Flow)
    • Continuous Integration
  • Language Support
    • Node.js
      • Node.js Behavior in Heroku
      • Working with Node.js
      • Troubleshooting Node.js Apps
    • Ruby
      • Rails Support
      • Working with Bundler
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Background Jobs in Python
      • Python Behavior in Heroku
      • Working with Django
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Working with Maven
      • Working with Spring Boot
      • Troubleshooting Java Apps
    • PHP
      • Working with PHP
      • PHP Behavior in Heroku
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
      • Migrating to Heroku Postgres
    • Heroku Key-Value Store
    • Apache Kafka on Heroku
    • Other Data Stores
  • AI
    • Working with AI
    • Heroku Inference
      • AI Models
      • Inference Essentials
      • Inference API
      • Quick Start Guides
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
      • Single Sign-on (SSO)
    • Private Spaces
      • Infrastructure Networking
    • Compliance
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Language Support
  • Ruby
  • Working with Ruby
  • Uploading Files to S3 in Ruby with Paperclip

This article was contributed by Tute Costa

Tute is a developer at thoughtbot NYC. You can find him on twitter @tutec .

Uploading Files to S3 in Ruby with Paperclip

English — 日本語に切り替える

Last updated December 02, 2024

Table of Contents

  • Prerequisites
  • Overview
  • Reference Application
  • Configuration
  • International users (additional configuration)
  • Define the file attribute in the Model
  • Update database
  • Upload form
  • Upload controller
  • Image display
  • Deploy

Many web apps require the user to upload images and other files for storage and processing. Paperclip is a cleanly abstracted Ruby library that reduces the complexity of file uploading and processing.

Using Paperclip with an external storage service such as Amazon S3 or Rackspace CloudFiles allows you to scale your application’s files and codebase independently. Such an architecture is required in highly elastic environments that distribute your application across multiple instances, such as Heroku.

This guide describes how to set up a Ruby on Rails application with image uploading via Paperclip and Amazon S3.

Prerequisites

  • AWS S3 Account for storing images in the cloud.
  • Heroku CLI to create and deploy web applications to Heroku.
  • ImageMagick for resizing images.

Note: Mac users can install ImageMagick with Homebrew brew install imagemagick. Windows users can use the Windows binary release.

Overview

Paperclip is an easy file attachment library for ActiveRecord. It treats files like model attributes. This means they aren’t saved to their final locations, nor are they deleted if set to nil, until ActiveRecord::Base#save is called. It can validate based on file size and presence. It can transform its assigned image into thumbnails if needed, and the only prerequisites are database columns and ImageMagick. Attached files are referenced in the browser by an understandable specification with sensible defaults.

Reference Application

Paperclip Demo Application

The reference application allows a user to manage a list of their friends.

  • Each friend will have an avatar with Paperclip providing the image upload and resizing functionality.
  • The app will demonstrate how to generate scaled down thumbnails, and display the resized images.
  • The application will also gracefully degrade to display a default image missing.png for friends without an avatar.

Download the source code from GitHub.

Configuration

Paperclip requires the following gems added to your Gemfile.

# Gemfile
gem 'paperclip'
gem 'aws-sdk', '~> 2.3'

Run bundle install and restart the Rails server after modifying the Gemfile.

We’ll also need to specify the AWS configuration variables for the production Environment.

# config/environments/production.rb
config.paperclip_defaults = {
  storage: :s3,
  s3_credentials: {
    bucket: ENV.fetch('S3_BUCKET_NAME'),
    access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
    secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'),
    s3_region: ENV.fetch('AWS_REGION'),
  }
}

To test S3 uploads locally in development mode these settings must also be added to the development environment.

Additionally, we’ll need to the set the AWS configuration variables on the Heroku application.

$ heroku config:set S3_BUCKET_NAME=your_bucket_name
$ heroku config:set AWS_ACCESS_KEY_ID=your_access_key_id
$ heroku config:set AWS_SECRET_ACCESS_KEY=your_secret_access_key
$ heroku config:set AWS_REGION=your_aws_region

International users (additional configuration)

If you are having issues uploading images please read the following two configuration sections.

If you continue to have issues please see the Paperclip documentation page for detailed configuration options.

To override the default URL structure and place the bucket’s name “domain-style” in the URL (e.g. your_bucket_name.s3.amazonaws.com). These options can be placed in the paperclip_defaults configuration hash shown above, or into an initializer.

# config/initializers/paperclip.rb
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:filename'

If you are seeing the following error: “The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.” Try setting the specified endpoint with the s3_host_name config var.

# config/initializers/paperclip.rb
Paperclip::Attachment.default_options[:s3_host_name] = 's3-us-west-2.amazonaws.com'

Define the file attribute in the Model

To add attachment functionality to the Friend model use the Paperclip helper method has_attached_file and a symbol with the desired name of the attachment.

class Friend < ActiveRecord::Base
  # This method associates the attribute ":avatar" with a file attachment
  has_attached_file :avatar, styles: {
    thumb: '100x100>',
    square: '200x200#',
    medium: '300x300>'
  }

  # Validate the attached image is image/jpg, image/png, etc
  validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
end
Additional ImageMagick resizing options can be found here

The has_attached_file method also accepts a styles hash that specifies the resize dimensions of the uploaded image. The > and # symbols will tell ImageMagick how the image will be resized (the > will proportionally reduce the size of the image).

Update database

A database migration is needed to add the avatar attribute on Friend in the database schema. Run the following rails helper method to generate a stub migration.

$ rails g migration AddAvatarToFriends

Paperclip comes with the migration helper methods add_attachment and remove_attachment. They are used to create the columns needed to store image data in the database. Use them in the AddAvatarToFriends migration.

class AddAvatarToFriends < ActiveRecord::Migration
  def self.up
    add_attachment :friends, :avatar
  end

  def self.down
    remove_attachment :friends, :avatar
  end
end

This migration will create avatar_file_name, avatar_file_size, avatar_content_type, and avatar_updated_at attributes on the Friend model. These attributes will be set automatically when files are uploaded.

Run the migrations with rake db:migrate to update your database.

Upload form

Images are uploaded to your application before being stored in S3. This allows your models to perform validations and other processing before being sent to S3.

Form with File Input

Add a file input field to the web form that allows users to browse and select images from their local filesystem.

Make sure the form has multipart: true added to it.

<%= form_for(@friend, multipart: true) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :avatar %>
    <%= f.file_field :avatar %>
  </div>
  <div class="actions">
    <%= f.submit 'Make a friend' %>
    <%= link_to 'Nevermind', friends_path, class: 'button' %>
  </div>
<% end %>

When the form is submitted and the backing models are successfully persisted to the database, the file itself will be uploaded to S3.

Upload controller

With Rails 4 we’ll need to specify the permitted params. We’ll permit :name and :avatar in the params.

class FriendsController < ApplicationController
  # Other CRUD actions omitted

  def create
    @friend = Friend.new(friend_params)

    if @friend.save
      redirect_to @friend, notice: 'Friend was successfully created.'
     else
       render action: 'new'
    end
  end

  private

  def friend_params
    params.require(:friend).permit(:avatar, :name)
  end
end

Large files uploads in single-threaded, non-evented environments (such as Rails) block your application’s web dynos and can cause request timeouts and H11, H12 errors. For files larger than 4mb the, use the direct upload method instead.

Image display

Files that have been uploaded with Paperclip are stored in S3. However, metadata such as the file’s name, location on S3, and last updated timestamp are all stored in the model’s table in the database.

Access the file’s url through the url method on the model’s file attribute (avatar in this example).

friend.avatar.url #=> https://your_bucket_name.s3.amazonaws.com/...

This url can be used directly in the view to display uploaded images.

<%= image_tag @friend.avatar.url(:square) %>

The url method can take a style (defined earlier in the Friend model) to access a specific processed version of the file.

Paperclip Demo Application

As these images are served directly from S3 they don’t interfere with other requests and allow your page to load quicker than serving directly from your app.

Display the medium sized image by passing :medium to the url method.

<%= image_tag @friend.avatar.url(:medium) %>

Deploy

Once you’ve updated your application to use Paperclip commit the modified files to git.

$ git commit -m "Upload friend images via Paperclip"

On deployment to Heroku you will need to migrate your database to support the required file columns.

$ git push heroku master
$ heroku run bundle exec rake db:migrate

Keep reading

  • Working with Ruby

Feedback

Log in to submit feedback.

Using WebSockets on Heroku with Ruby Using WebSockets on Heroku with Ruby

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices