Caching Images Using Attachment_Fu and Amazon S3
Caching images improves the user experience and reduces S3 costs. It improves the user’s experience because web pages load quicker and it reduces S3 costs since you have fewer transfers.
When using the attachment_fu plugin and the AWS::S3 gem, there are two things we need to do to cache images using attachment_fu and Amazon S3.
- Set the Cache-Control http header.
- Make S3 urls expire at a consistent time.
Setting the Cache-Control header tells our web browser that the cached image is valid and that it doesn’t need to check for an updated copy of the image on the server. Making the url expire at a consistent time gives our images that are the same a consistent url, so our browser doesn’t get confused and think they are different images. For example, image.jpg?expires=100 appears to our browser as a different image than image.jpg?expires=101.
Set Cache-Control Header in AWS S3
The technique we use for setting the Cache-Control header was originally posted in this guide. We’ll enhance the AWS::S3 store method to add a Cache-Control header that’s 10 years in the future if there isn’t already a Cache-Conrol header present. The first step is to create a file in your lib/ folder and name it s3_cache_control.rb.
# Adjusts the cache control to the maximum value of 10 years (315360000 seconds)
module AWS
module S3
class S3Object
class << self
def store_with_cache_control(key, data, bucket = nil, options = {})
if (options['Cache-Control'].blank?)
options['Cache-Control'] = 'max-age=315360000'
end
store_without_cache_control(key, data, bucket, options)
end
alias_method_chain :store, :cache_control
end
end
end
end
Make S3 URLs Expire at a Consistent Time
We’re going to make generated S3 URLs expire at a consistent time by overriding attachment_fu’s authenticated_s3_url method. You can view the original authenticated_s3_url method. We’re going to override it to add an expires option in there isn’t one present. Place this code in lib/s3_cache_control.rb.
require 'technoweenie/attachment_fu/backends/s3_backend'
module Technoweenie
module AttachmentFu
module Backends
module S3Backend
def authenticated_s3_url(*args)
options = args.extract_options!
options[:expires] = Time.now.advance(:minutes => 5).end_of_day.to_i if options[:expires].blank? and options[:expires_on].blank?
thumbnail = args.shift
S3Object.url_for(full_filename(thumbnail), bucket_name, options)
end
end
end
end
end
You can set expires to whatever value you would like, as long as its consistent. In our case it made since to do it at the end of the day. But it could be at the end of the hour if you didn’t want photos cached long, or at the end of the week if you wanted them cached longer.
Now just add these two lines to your config/environment.rb file and you’re set:
require 'aws/s3' require 's3_cache_control'

