Skip to content

Commit

Permalink
Updated attachment_fu to add CloudFront support.
Browse files Browse the repository at this point in the history
  • Loading branch information
Micah Wedemeyer committed Mar 15, 2009
1 parent ab1e4f7 commit 48639bf
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 1 deletion.
3 changes: 3 additions & 0 deletions amazon_s3.yml.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ development:
bucket_name: appname_development
access_key_id:
secret_access_key:
distribution_domain: XXXX.cloudfront.net

test:
bucket_name: appname_test
access_key_id:
secret_access_key:
distribution_domain: XXXX.cloudfront.net

production:
bucket_name: appname
access_key_id:
secret_access_key:
distribution_domain: XXXX.cloudfront.net
3 changes: 3 additions & 0 deletions lib/technoweenie/attachment_fu.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ module ActMethods
# for the S3 backend. Setting this sets the :storage to :file_system.

# * <tt>:storage</tt> - Use :file_system to specify the attachment data is stored with the file system. Defaults to :db_system.
# * <tt>:cloundfront</tt> - Set to true if you are using S3 storage and want to serve the files through CloudFront. You will need to
# set a distribution domain in the amazon_s3.yml config file. Defaults to false
# * <tt>:bucket_key</tt> - Use this to specify a different bucket key other than :bucket_name in the amazon_s3.yml file. This allows you to use
# different buckets for different models. An example setting would be :image_bucket and the you would need to define the name of the corresponding
# bucket in the amazon_s3.yml file.
Expand Down Expand Up @@ -80,6 +82,7 @@ def has_attachment(options = {})
options[:thumbnails] ||= {}
options[:thumbnail_class] ||= self
options[:s3_access] ||= :public_read
options[:cloudfront] ||= false
options[:content_type] = [options[:content_type]].flatten.collect! { |t| t == :image ? Technoweenie::AttachmentFu.content_types : t }.flatten unless options[:content_type].nil?

unless options[:thumbnails].is_a?(Hash)
Expand Down
52 changes: 51 additions & 1 deletion lib/technoweenie/attachment_fu/backends/s3_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,28 @@ module Backends
# If you don't already have your access keys, all you need to sign up for the S3 service is an account at Amazon.
# You can sign up for S3 and get access keys by visiting http://aws.amazon.com/s3.
#
# If you wish to use Amazon CloudFront to serve the files, you can also specify a distibution domain for the bucket.
# To read more about CloudFront, visit http://aws.amazon.com/cloudfront
#
# Example configuration (RAILS_ROOT/config/amazon_s3.yml)
#
# development:
# bucket_name: appname_development
# access_key_id: <your key>
# secret_access_key: <your key>
# distribution_domain: XXXX.cloudfront.net
#
# test:
# bucket_name: appname_test
# access_key_id: <your key>
# secret_access_key: <your key>
# distribution_domain: XXXX.cloudfront.net
#
# production:
# bucket_name: appname
# access_key_id: <your key>
# secret_access_key: <your key>
# distribution_domain: XXXX.cloudfront.net
#
# You can change the location of the config path by passing a full path to the :s3_config_path option.
#
Expand All @@ -59,6 +65,8 @@ module Backends
# * <tt>:server</tt> - The server to make requests to. Defaults to <tt>s3.amazonaws.com</tt>.
# * <tt>:port</tt> - The port to the requests should be made on. Defaults to 80 or 443 if <tt>:use_ssl</tt> is set.
# * <tt>:use_ssl</tt> - If set to true, <tt>:port</tt> will be implicitly set to 443, unless specified otherwise. Defaults to false.
# * <tt>:distribution_domain</tt> - The CloudFront distribution domain for the bucket. This can either be the assigned
# distribution domain (ie. XXX.cloudfront.net) or a chosen domain using a CNAME. See CloudFront for more details.
#
# == Usage
#
Expand Down Expand Up @@ -150,6 +158,16 @@ module Backends
#
# Niether <tt>base_path</tt> or <tt>full_filename</tt> include the bucket name as part of the path.
# You can retrieve the bucket name using the <tt>bucket_name</tt> method.
#
# === Accessing CloudFront URLs
#
# You can get an object's CloudFront URL using the cloudfront_url accessor. Using the example from above:
# @postcard.cloudfront_url # => http://XXXX.cloudfront.net/photos/1/mexico.jpg
#
# The resulting url is in the form: http://:distribution_domain/:table_name/:id/:file
#
# If you set :cloudfront to true in your model, the public_filename will be the CloudFront
# URL, not the S3 URL.
module S3Backend
class RequiredLibraryNotFoundError < StandardError; end
class ConfigFileNotFoundError < StandardError; end
Expand Down Expand Up @@ -198,6 +216,10 @@ def self.hostname
def self.port_string
@port_string ||= (s3_config[:port].nil? || s3_config[:port] == (s3_config[:use_ssl] ? 443 : 80)) ? '' : ":#{s3_config[:port]}"
end

def self.distribution_domain
@distribution_domain = s3_config[:distribution_domain]
end

module ClassMethods
def s3_protocol
Expand All @@ -211,6 +233,10 @@ def s3_hostname
def s3_port_string
Technoweenie::AttachmentFu::Backends::S3Backend.port_string
end

def cloudfront_distribution_domain
Technoweenie::AttachmentFu::Backends::S3Backend.distribution_domain
end
end

# Overwrites the base filename writer in order to store the old filename
Expand Down Expand Up @@ -249,7 +275,27 @@ def full_filename(thumbnail = nil)
def s3_url(thumbnail = nil)
File.join(s3_protocol + s3_hostname + s3_port_string, bucket_name, full_filename(thumbnail))
end
alias :public_filename :s3_url

# All public objects are accessible via a GET request to CloudFront. You can generate a
# url for an object using the cloudfront_url method.
#
# @photo.cloudfront_url
#
# The resulting url is in the form: <tt>http://:distribution_domain/:table_name/:id/:file</tt> using
# the <tt>:distribution_domain</tt> variable set in the configuration parameters in <tt>RAILS_ROOT/config/amazon_s3.yml</tt>.
#
# The optional thumbnail argument will output the thumbnail's filename (if any).
def cloudfront_url(thumbnail = nil)
"http://" + cloudfront_distribution_domain + "/" + full_filename(thumbnail)
end

def public_filename(*args)
if attachment_options[:cloudfront]
cloudfront_url(args)
else
s3_url(args)
end
end

# All private objects are accessible via an authenticated GET request to the S3 servers. You can generate an
# authenticated url for an object like this:
Expand Down Expand Up @@ -301,6 +347,10 @@ def s3_hostname
def s3_port_string
Technoweenie::AttachmentFu::Backends::S3Backend.port_string
end

def cloudfront_distribution_domain
Technoweenie::AttachmentFu::Backends::S3Backend.distribution_domain
end

protected
# Called in the after_destroy callback
Expand Down

0 comments on commit 48639bf

Please sign in to comment.