One of our projects needed to copy lots of files between different S3 buckets, and Amazon just came out with their beta version for Copying s3 objects. So, we decided it would be handy to use this new feature. Instead of downloading each file then uploading it back to S3, which was the only official way to do this before this feature came out.
We also found that the gem did not include an argument to copy/rename objects between different buckets. So we make a patch to the s3 gem to use the new Copy API and accept an extra argument for the destination bucket. We found it more useful, for us, to have this ability.
copy_patch.diff:
1 Index: lib/aws/s3/object.rb
2 ===================================================================
3 --- lib/aws/s3/object.rb (revision 1282)
4 +++ lib/aws/s3/object.rb (working copy)
5 @@ -178,19 +178,19 @@
6 end
7 end
8
9 -
10 - def copy(key, copy_key, bucket = nil, options = {})
11 - bucket = bucket_name(bucket)
12 - original = open(url_for(key, bucket))
13 +
14 + def copy(key, copy_key, src_bucket = nil, dest_bucket = nil, options = {})
15 + src_bucket = bucket_name(src_bucket)
16 + dest_bucket = bucket_name(dest_bucket)
17 + original = open(url_for(key, src_bucket))
18 default_options = {:content_type => original.content_type}
19 - store(copy_key, original, bucket, default_options.merge(options))
20 - acl(copy_key, bucket, acl(key, bucket))
21 + copy(key, copy_key, src_bucket, dest_bucket, options)
22 end
23
24 -
25 - def rename(from, to, bucket = nil, options = {})
26 - copy(from, to, bucket, options)
27 - delete(from, bucket)
28 +
29 + def rename(from, to, src_bucket = nil, dest_bucket = nil, options = {})
30 + copy(from, to, src_bucket, dest_bucket, options)
31 + delete(from, src_bucket)
32 end
33
34
35 @@ -238,8 +238,35 @@
36
37 put(path, options, data)
38 end
39 +
40 +
41 +
42 + def copy(source_key, dest_key, source_bucket = nil, dest_bucket = nil, options = {})
43 + validate_key!(dest_key)
44 +
45 + path1 = path!(dest_bucket, dest_key, options)
46 + path2 = path!(source_bucket, source_key, options)
47 + infer_content_type!(dest_key, options)
48 + options['x-amz-copy-source'] = path2
49 + options['x-amz-metadata-directive'] = 'COPY'
50 + put(path1, options)
51 + end
52 +
53 alias_method :create, :store
54 alias_method :save, :store
55 +
56 +
57 + def copy(source_key, dest_key, source_bucket = nil, dest_bucket = nil, options = {})
58 + validate_key!(dest_key)
59 +
60 + path1 = path!(dest_bucket, dest_key, options)
61 + path2 = path!(source_bucket, source_key, options)
62 + infer_content_type!(dest_key, options)
63 + options['x-amz-copy-source'] = path2
64 + options['x-amz-metadata-directive'] = 'COPY'
65 + put(path1, options)
66 + end
67 +
68
69
70
Just run this patch in your gem directory and change all references in to copy and rename to include the destination bucket in the arguments. I suggest freezing your gem and executing the patch in the vendor/gems/aws-s3 directory, so you would not be changing your gem for all your previous projects and break them.
Since you're already modifying your aws-s3 gem, it might be worthwhile to also add an Expires and Cache-Control Header to your static assets (images, javascripts, and css). This will make the browser cache files for 3 years (don't worry, if you change the file, S3 will still update the cache-control header) and make YSlow happy.