How to get Paperclip and AWS-S3 Singapore (and European) buckets working

Getting the AWS-S3 and Paperclip plugins to work with Singapore (and European) Buckets in S3 is not as straightforward as it seems.

In fact, if you’ve followed most of the guides out there, you’ll probably get an error like:

The bucket you are attempting to access must be addressed using the specified
endpoint. Please send all future requests to this endpoint

Right now, there’s currently a bug in which non-US bucket URL is not being probably embedded with the aws/s3 plugin and in order to get your Singapore/European buckets to play nice, you’re going to need to make changes to your code.

I hope this guide will be able to save you some time as it has for me.

Step 1: Install aws-s3 and paperclip gem

# Gemfile
gem 'aws-s3'
gem 'paperclip'

Step 2: Get your paperclip models in order.

Step 3: Rewrite your paperclip model to look something like:

# your model
  has_attached_file :photo,
     :storage => :s3,
     :s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
     # if you're using Rails 3.x, please use #{Rails.root.to_s} instead of #{RAILS_ROOT}
     :path => "/:style/:id/:filename",
     :url  => ":s3_sg_url" # if you're using eu buckets, call it s3_eu_url

Step 4: Create a new file s3.yml in /config and fill in your authentication details. You can edit this file to add different configurations for different buckets.

#/config/s3.yml
development:
  bucket: <appname>-dev
  access_key_id: <aws_access_key_id>
  secret_access_key: <aws_secret_access_key>

test:
  bucket: <appname>-test
  access_key_id: <aws_access_key_id>
  secret_access_key: <aws_secret_access_key>

production:
  bucket: <appname>-production
  access_key_id: <aws_access_key_id>
  secret_access_key: <aws_secret_access_key>

Step 5: Create a new file /config/initializer/s3.rb

# /config/initializer/s3.rb
# if you're using sg buckets
Paperclip.interpolates(:s3_sg_url) { |attachment, style|
   "#{attachment.s3_protocol}://s3-ap-southeast-1.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/},
   "")}"
   }

# if you're using eu buckets
Paperclip.interpolates(:s3_eu_url) { |attachment, style|
  "#{attachment.s3_protocol}://s3-eu-west-1.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
}

Step 6: Update your environments.rb. Add the following

# /config/environments.rb
require 'aws/s3'
AWS::S3::DEFAULT_HOST = "s3-ap-southeast-1.amazonaws.com" # if using sg buckets

# or

AWS::S3::DEFAULT_HOST = "s3-eu-west-1.amazonaws.com" #if using eu buckets.                                                   

And there you have it. Your paperclip should now upload files directly to s3 without any hiccups!

Let me know if you find this guide useful!