Commit 723618a2 by Jon Yurek

S3 CNAME support

parent 53ff5f9f
...@@ -346,6 +346,10 @@ module Paperclip ...@@ -346,6 +346,10 @@ module Paperclip
return true if callback(:"#{which}_#{name}_post_process") == false return true if callback(:"#{which}_#{name}_post_process") == false
end end
def callback which #:nodoc:
instance.run_callbacks(which, @queued_for_write){|result, obj| result == false }
end
def post_process_styles def post_process_styles
log("Post-processing #{name}") log("Post-processing #{name}")
@styles.each do |name, args| @styles.each do |name, args|
...@@ -362,10 +366,6 @@ module Paperclip ...@@ -362,10 +366,6 @@ module Paperclip
end end
end end
def callback which #:nodoc:
instance.run_callbacks(which, @queued_for_write){|result, obj| result == false }
end
def interpolate pattern, style = default_style #:nodoc: def interpolate pattern, style = default_style #:nodoc:
interpolations = self.class.interpolations.sort{|a,b| a.first.to_s <=> b.first.to_s } interpolations = self.class.interpolations.sort{|a,b| a.first.to_s <=> b.first.to_s }
interpolations.reverse.inject( pattern.dup ) do |result, interpolation| interpolations.reverse.inject( pattern.dup ) do |result, interpolation|
......
...@@ -108,11 +108,18 @@ module Paperclip ...@@ -108,11 +108,18 @@ module Paperclip
# Paperclip will attempt to create it. The bucket name will not be interpolated. # Paperclip will attempt to create it. The bucket name will not be interpolated.
# You can define the bucket as a Proc if you want to determine it's name at runtime. # You can define the bucket as a Proc if you want to determine it's name at runtime.
# Paperclip will call that Proc with attachment as the only argument. # Paperclip will call that Proc with attachment as the only argument.
# * +url+: There are two options for the S3 url. You can choose to have the bucket's name # * +url+: There are three options for the S3 url. You can choose to have the bucket's name
# placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket). # placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket).
# Lastly, you can specify a CNAME (which requires the CNAME to be specified as
# :s3_cname. You can read more about CNAMEs and S3 at
# http://docs.amazonwebservices.com/AmazonS3/latest/index.html?VirtualHosting.html
# Normally, this won't matter in the slightest and you can leave the default (which is # Normally, this won't matter in the slightest and you can leave the default (which is
# path-style, or :s3_path_url). But in some cases paths don't work and you need to use # path-style, or :s3_path_url). But in some cases paths don't work and you need to use
# the domain-style (:s3_domain_url). Anything else here will be treated like path-style. # the domain-style (:s3_domain_url). Anything else here will be treated like path-style.
# NOTE: If you use a CNAME for use with CloudFront, you can NOT specify https as your
# :s3_protocol; This is *not supported* by S3/CloudFront. Finally, when using the host
# alias, the :bucket parameter is ignored, as the hostname is used as the bucket name
# by S3.
# * +path+: This is the key under the bucket in which the file will be stored. The # * +path+: This is the key under the bucket in which the file will be stored. The
# URL will be constructed from the bucket and the path. This is what you will want # URL will be constructed from the bucket and the path. This is what you will want
# to interpolate. Keys should be unique, like filenames, and despite the fact that # to interpolate. Keys should be unique, like filenames, and despite the fact that
...@@ -129,8 +136,12 @@ module Paperclip ...@@ -129,8 +136,12 @@ module Paperclip
@s3_permissions = @options[:s3_permissions] || 'public-read' @s3_permissions = @options[:s3_permissions] || 'public-read'
@s3_protocol = @options[:s3_protocol] || (@s3_permissions == 'public-read' ? 'http' : 'https') @s3_protocol = @options[:s3_protocol] || (@s3_permissions == 'public-read' ? 'http' : 'https')
@s3_headers = @options[:s3_headers] || {} @s3_headers = @options[:s3_headers] || {}
@s3_host_alias = @options[:s3_host_alias]
@url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/) @url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/)
end end
base.class.interpolations[:s3_alias_url] = lambda do |attachment, style|
"#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}"
end
base.class.interpolations[:s3_path_url] = lambda do |attachment, style| base.class.interpolations[:s3_path_url] = lambda do |attachment, style|
"#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}" "#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
end end
...@@ -154,6 +165,10 @@ module Paperclip ...@@ -154,6 +165,10 @@ module Paperclip
@bucket @bucket
end end
def s3_host_alias
@s3_host_alias
end
def parse_credentials creds def parse_credentials creds
creds = find_credentials(creds).stringify_keys creds = find_credentials(creds).stringify_keys
(creds[ENV['RAILS_ENV']] || creds).symbolize_keys (creds[ENV['RAILS_ENV']] || creds).symbolize_keys
......
...@@ -37,6 +37,55 @@ class StorageTest < Test::Unit::TestCase ...@@ -37,6 +37,55 @@ class StorageTest < Test::Unit::TestCase
end end
end end
context "" do
setup do
rebuild_model :storage => :s3,
:s3_credentials => {},
:bucket => "bucket",
:path => ":attachment/:basename.:extension",
:url => ":s3_path_url"
@dummy = Dummy.new
@dummy.avatar = StringIO.new(".")
end
should "return a url based on an S3 path" do
assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
end
end
context "" do
setup do
rebuild_model :storage => :s3,
:s3_credentials => {},
:bucket => "bucket",
:path => ":attachment/:basename.:extension",
:url => ":s3_domain_url"
@dummy = Dummy.new
@dummy.avatar = StringIO.new(".")
end
should "return a url based on an S3 subdomain" do
assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url
end
end
context "" do
setup do
rebuild_model :storage => :s3,
:s3_credentials => {
:production => { :bucket => "prod_bucket" },
:development => { :bucket => "dev_bucket" }
},
:s3_host_alias => "something.something.com",
:path => ":attachment/:basename.:extension",
:url => ":s3_alias_url"
@dummy = Dummy.new
@dummy.avatar = StringIO.new(".")
end
should "return a url based on the host_alias" do
assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url
end
end
context "Parsing S3 credentials with a bucket in them" do context "Parsing S3 credentials with a bucket in them" do
setup do setup do
rebuild_model :storage => :s3, rebuild_model :storage => :s3,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment