Make attachment_fu and Refinery CMS work with Amazon S3 EU buckets

April 6, 2010 — 2 Comments

Problem: You need to use attachment_fu for uploads in Rails, and would like to store your uploads in an Amazon S3 EU bucket. Amazon updated their API long ago, when they made EU buckets available, but for some reason the defacto standard library for working with S3 from Ruby, AWS::S3, was never updated to support the new API. As a result, you still can’t use the original AWS::S3, if you prefer storing your uploads on Amazons servers in Europe.

Now, there are other libraries that support EU buckets, like RightAWS or S3, but the upload plugin you use (in this case attachment_fu) has to support it. Previously the solution would be to switch to a different upload plugin that used another library, like Paperclip, but last time I checked, Paperclip had replaced RightAWS with AWS::S3. You might also for some reason not be able to switch to a different upload plugin.

On a recent project I was using the excellent Refinery CMS, which comes integrated with attachment_fu. I figured the problem using S3 EU buckets had been long solved, but apparently not, so here is the solution I cooked up:

# Install sauberia’s fork of AWS::S3: http://github.com/sauberia/aws-s3 either as a gem or a plugin in your Rails project.
# Install the attachment_fu plugin (Refinery CMS already has this): http://github.com/technoweenie/attachment_fu
# Patch attachment_fu to generate URLs that work correctly with Amazon S3 EU buckets, by using the code shown below:


# save this as vendor/plugins/attachment_fu_hacks/init.rb

require 'aws/s3'

Technoweenie::AttachmentFu::Backends::S3Backend.module_eval do
  # Hacked to use new S3 addressing, which lets us use EU buckets.
  # Requires sauberia's fork of aws-3s: http://github.com/sauberia/aws-s3
  #
  # All public objects are accessible via a GET request to the S3 servers. You can generate a
  # url for an object using the s3_url method.
  #
  #   @photo.s3_url
  #
  # The resulting url is in the form: http(s)://:bucket_name.:server/:table_name/:id/:file where
  # the :server variable defaults to AWS::S3 URL::DEFAULT_HOST (s3.amazonaws.com) and can be
  # set using the configuration parameters in RAILS_ROOT/config/amazon_s3.yml.
  #
  # The optional thumbnail argument will output the thumbnail's filename (if any).
  def s3_url(thumbnail = nil)
    File.join(s3_protocol + bucket_name + '.' + s3_hostname + s3_port_string, full_filename(thumbnail))
  end
end

Disclaimer: I have only tested this with Rails 2.3.5.

Update November 08, 2010:

It seems that Amazon updated the S3 API sometime around the end of October 2010. To successfully upload you now have to use a region-specific endpoint. If you followed this guide, you need to add “server: s3-eu-west-1.amazonaws.com” to your config/amazon_s3.yml file.

See this post for further details: Issues using Amazon S3 European Buckets.

2 responses to Make attachment_fu and Refinery CMS work with Amazon S3 EU buckets

  1. 

    Thank you, thank you, thank you! This was starting to grate me for an hour or so.

  2. 

    Thanks a lot, it made my day after searching for 4 hours how to fix a fucking legacy app !

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s