S3の操作するコードを書くタスクは日常的にやるわけではなくて、なぜかちょうど忘れた頃の絶妙なタイミングでやってきます。そのたびにAPIリファレンスを見ながら頑張って組み立ててるような気がしたので、しゃらくせぇ!と思い、よく使うやつをまとめました。
Aws::S3::ClientとAws::S3::Resourceの2系統を用意しました。お好みに応じて参照してください。
参考までに、この2つの違いがよく分からなくて途方に暮れている人はこちらをご覧ください。
AWS SDK for Ruby V3のAws::S3::ClientとAws::S3::Resourceの違いに正面から向き合う
クレデンシャル情報やリージョンは、環境変数やIAMロール等で設定されているものとします。
個別に設定する場合は、Aws::S3::Client.newやAws::S3::Resource.newの引数に渡してあげてください。
Aws::S3::Client
# 共通
client = Aws::S3::Client.new
バケット一覧
# バケット情報一覧
client.list_buckets
=> #<struct Aws::S3::Types::ListBucketsOutput
 buckets=
  [#<struct Aws::S3::Types::Bucket name="bucket-01", creation_date=2017-09-16 14:07:03 UTC>,
   #<struct Aws::S3::Types::Bucket name="bucket-02", creation_date=2018-08-19 04:22:41 UTC>,],
 owner=#<struct Aws::S3::Types::Owner display_name="XXXXXX", id="xxxxxxxxxxxxxxx">>
 
# 各バケットを操作
client.list_buckets.buckets.each do |bucket|
  # なにかする
end
バケット作成
client.create_bucket(bucket: "bucket-03")
=> #<struct Aws::S3::Types::CreateBucketOutput location="http://bucket-03.s3.amazonaws.com/">
バケット削除
client.delete_bucket(bucket: "bucket-03")
=> #<struct Aws::EmptyStructure>
オブジェクト一覧
# オブジェクト情報一覧
# `list_objects`は使わない
client.list_objects_v2(bucket: "bucket-01")
=> #<struct Aws::S3::Types::ListObjectsV2Output
 is_truncated=true,
 contents=
  [#<struct Aws::S3::Types::Object key="example_01.txt", last_modified=2019-09-24 21:42:10 UTC, etag="\"xxxxxxxxxxxxxx\"", size=7, storage_class="STANDARD", owner=nil>,
   #<struct Aws::S3::Types::Object key="example_02.txt", last_modified=2019-09-24 21:42:10 UTC, etag="\"xxxxxxxxxxxxxx\"", size=7, storage_class="STANDARD", owner=nil>],
 name="bucket-01",
 prefix="",
 delimiter=nil,
 max_keys=1000,
 common_prefixes=[],
 encoding_type=nil,
 key_count=1000,
 continuation_token=nil,
 next_continuation_token="1I+AdtAyjlXhJ1jEKpdpR3fqz2bDnfJFEfZ+wgn9vmpXjHNGcLzL8bg==",
 start_after=nil>
 
# 各オブジェクトを操作(1000個以下の場合)
client.list_objects_v2(bucket: "bucket-01").contents.each do |object|
  # なにかする
end
# 各オブジェクトを操作(1000個より多いの場合)
options = {bucket: "bucket-01"}
loop do
  object_list = client.list_objects_v2(options)
  object_list.contents.each do |object|
    # なにかする
  end
  options[:continuation_token] = object_list.next_continuation_token
  break unless object_list.next_continuation_token
end
# キー名のプレフィクスによる絞り込み
client.list_objects_v2(bucket: "bucket-01", prefix: "hoge/").contents.each do |object|
  # なにかする
end
オブジェクトアップロード
client.put_object(bucket: "bucket-01", key: "example_01.txt", body: "example")
=> #<struct Aws::S3::Types::PutObjectOutput
 expiration=nil,
 etag="\"xxxxxxxxxxxxxx\"",
 server_side_encryption=nil,
 version_id="JlDwEydDxlVNoyEaChzromzkjPo5FwVl",
 sse_customer_algorithm=nil,
 sse_customer_key_md5=nil,
 ssekms_key_id=nil,
 ssekms_encryption_context=nil,
 request_charged=nil>
オブジェクト読み込み
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#get_object-instance_method
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Types/GetObjectOutput.html
client.get_object(bucket: "bucket-01", :key => 'example_01.txt').body.read
=> "example"
オブジェクト削除
client.delete_object(bucket: "bucket-01", key: "example_01.txt")
=> #<struct Aws::S3::Types::DeleteObjectOutput delete_marker=true, version_id="skCZWAXC0.vhxjK6zKTF0dBkj4H0gEe8", request_charged=nil>
オブジェクトのバージョン操作
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#list_object_versions-instance_method
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#delete_object-instance_method
# バージョン情報
client.list_object_versions(bucket: "bucket-01", prefix: "example_01.txt")
=> #<struct Aws::S3::Types::ListObjectVersionsOutput
 is_truncated=false,
 key_marker="",
 version_id_marker="",
 next_key_marker=nil,
 next_version_id_marker=nil,
 versions=
  [#<struct Aws::S3::Types::ObjectVersion
  etag="\"xxxxxxxxxx\"",
  size=7,
  storage_class="STANDARD",
  key="example_01.txt",
  version_id="BcczH4ZRVunnKyBuzk3cBOQgrh1gtGpR",
  is_latest=true,
  last_modified=2019-09-24 21:47:54 UTC,
  owner=#<struct Aws::S3::Types::Owner display_name="xxxxxx", id="xxxxxxxxxxxxxxxxxx">>,
 #<struct Aws::S3::Types::ObjectVersion
  etag="\"xxxxxxxxxx\"",
  size=7,
  storage_class="STANDARD",
  key="example_01.txt",
  version_id="null",
  is_latest=false,
  last_modified=2019-09-24 21:42:10 UTC,
  owner=#<struct Aws::S3::Types::Owner display_name="xxxxxx", id="xxxxxxxxxxxxxxxxxx">>],
 name="bucket-01",
 prefix="example_01.txt",
 delimiter=nil,
 max_keys=1000,
 common_prefixes=[],
 encoding_type="url">
 
# 特定のバージョンを削除
client.delete_object(bucket: "bucket-01", prefix: "example_01.txt", version_id: "JlDwEydDxlVNoyEaChzromzkjPo5FwVl")
=> #<struct Aws::S3::Types::DeleteObjectOutput delete_marker=nil, version_id="JlDwEydDxlVNoyEaChzromzkjPo5FwVl", request_charged=nil>
マルチパートアップロード
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#create_multipart_upload-instance_method
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#upload_part-instance_method
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#complete_multipart_upload-instance_method
multipart = client.create_multipart_upload(bucket: "bucket-01", key: "multipart")
=> #<struct Aws::S3::Types::CreateMultipartUploadOutput
 abort_date=nil,
 abort_rule_id=nil,
 bucket="bucket-01",
 key="multipart",
 upload_id="xxxxxxxxxxxxxxxxxxxx",
 server_side_encryption=nil,
 sse_customer_algorithm=nil,
 sse_customer_key_md5=nil,
 ssekms_key_id=nil,
 ssekms_encryption_context=nil,
 request_charged=nil>
part_01 = client.upload_part(bucket: "bucket-01", key: "multipart", body: File.open("/path/to/part_01"), part_number: 1, upload_id: multipart.upload_id)
=> #<struct Aws::S3::Types::UploadPartOutput
 server_side_encryption=nil,
 etag="\"xxxxxxxxxxxxxxxxxxxxx\"",
 sse_customer_algorithm=nil,
 sse_customer_key_md5=nil,
 ssekms_key_id=nil,
 request_charged=nil>
part_02 = client.upload_part(bucket: "bucket-01", key: "multipart", body: File.open("/path/to/part_02"), part_number: 2, upload_id: multipart.upload_id)
=> #<struct Aws::S3::Types::UploadPartOutput
 server_side_encryption=nil,
 etag="\"yyyyyyyyyyyyyyyyyyyyy\"",
 sse_customer_algorithm=nil,
 sse_customer_key_md5=nil,
 ssekms_key_id=nil,
 request_charged=nil>
client.complete_multipart_upload(
  bucket: "bucket-name-0001",
  key: "multipart",
  multipart_upload: {
    parts: [
      {etag: part_01.etag, part_number: 1},
      {etag: part_02.etag, part_number: 2}
    ]
  },
  upload_id: multipart.upload_id
)
=> #<struct Aws::S3::Types::CompleteMultipartUploadOutput
 location="https://bucket-01.s3.ap-northeast-1.amazonaws.com/multipart",
 bucket="bucket-01",
 key="multipart",
 expiration=nil,
 etag="\"zzzzzzzzzzzzzzzzzzzzz\"",
 server_side_encryption=nil,
 version_id="CSbIGreIivX2CTbIxj9Qz1JbePVQb2Qo",
 ssekms_key_id=nil,
 request_charged=nil>
署名付きURL作成
# clientではできない
signer = Aws::S3::Presigner.new
signer.presigned_url(:get_object, bucket: "bucket-01", key: "example_01.txt", expires_in: 3600)
=> "https://bucket-01.s3.ap-northeast-1.amazonaws.com/example_0001?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-...
Aws::S3::Resource
# 共通
resource = Aws::S3::Resource.new
バケット一覧
# バケット情報一覧
resource.buckets
=> #<Aws::S3::Bucket::Collection:0x00007fb1e3ccb6a8 @batches=#<Enumerator: ...>, @limit=nil, @size=nil>
# 各バケットを操作
resource.buckets.each do |bucket|
  # なにかする
end
バケット作成
resource.create_bucket(bucket: "bucket-03")
=> #<Aws::S3::Bucket:0x00007fb1e3d3f2d8 @client=#<Aws::S3::Client>, @data=nil, @name="bucket-03">
# こちらでもできるけど、Client系統で扱うbucket情報が返ってくる
resource.bucket("bucket-03").create
# 存在確認もできる
resource.bucket("bucket-03").exists?
=> true
バケット削除
resource.bucket("bucket-03").delete
=> #<struct Aws::EmptyStructure>
オブジェクト一覧
bucket = resource.bucket("bucket-01")
# オブジェクト情報
bucket.objects
=> #<Aws::S3::ObjectSummary::Collection:0x00007fb1e3e47a68 @batches=#<Enumerator: ...>, @limit=nil, @size=nil>
# 各オブジェクトを操作(1000個より多くてもOK!)
bucket.objects.each do |object|
  # なにかする
end
# キー名のプレフィクスによる絞り込み
bucket.objects(prefix: "hoge/").each do |object|
  # なにかする
end
オブジェクトアップロード
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Bucket.html#put_object-instance_method
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#put-instance_method
bucket = resource.bucket("bucket-01")
# 文字列から
bucket.put_object(key: "example_01.txt", body: "example")
=> #<Aws::S3::Object:0x00007f859e9625c8 @bucket_name="bucket-01", @client=#<Aws::S3::Client>, @data=nil, @key="example_01.txt">
# ファイルから
bucket.put_object(key: "example_01.txt", body: File.open("example_01.txt"))
=> #<Aws::S3::Object:0x00007f859e9625c8 @bucket_name="bucket-01", @client=#<Aws::S3::Client>, @data=nil, @key="example_01.txt">
# こちらでもできるけど、Client系統で扱うbucket情報が返ってくる
bucket.object("example_01.txt").put(body: "example")
=> #<struct Aws::S3::Types::PutObjectOutput
 expiration=nil,
 etag="\"xxxxxxxxxxxxxxxxxxxxxxxxxxxx\"",
 server_side_encryption=nil,
 version_id=nil,
 sse_customer_algorithm=nil,
 sse_customer_key_md5=nil,
 ssekms_key_id=nil,
 ssekms_encryption_context=nil,
 request_charged=nil>
オブジェクト読み込み
bucket = resource.bucket("bucket-01")
bucket.object("example_01.txt").get.body.read
=> "example"
# 存在確認もできる
bucket.object("example_01.txt").exists?
=> true
オブジェクト削除
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Bucket.html#delete-instance_method
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/ObjectSummary/Collection.html#batch_delete!-instance_method
bucket = resource.bucket("bucket-01")
bucket.object("example_01.txt").delete
=> #<struct Aws::S3::Types::DeleteObjectOutput delete_marker=nil, version_id=nil, request_charged=nil>
# 一括削除
bucket.objects(prefix: "hoge/").batch_delete!
=> nil
オブジェクトのバージョン操作
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Bucket.html#object_versions-instance_method
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#delete-instance_method
bucket = resource.bucket("bucket-01")
bucket.object_versions(prefix: "example_01.txt").map(&:data)
=> [#<struct Aws::S3::Types::ObjectVersion
  etag="\"xxxxxxxxxx\"",
  size=7,
  storage_class="STANDARD",
  key="example_01.txt",
  version_id="BcczH4ZRVunnKyBuzk3cBOQgrh1gtGpR",
  is_latest=true,
  last_modified=2019-09-24 21:47:54 UTC,
  owner=#<struct Aws::S3::Types::Owner display_name="xxxxxx", id="xxxxxxxxxxxxxxxxxx">>,
 #<struct Aws::S3::Types::ObjectVersion
  etag="\"xxxxxxxxxx\"",
  size=7,
  storage_class="STANDARD",
  key="example_01.txt",
  version_id="null",
  is_latest=false,
  last_modified=2019-09-24 21:42:10 UTC,
  owner=#<struct Aws::S3::Types::Owner display_name="xxxxxx", id="xxxxxxxxxxxxxxxxxx">>]
  
# 特定のバージョンを削除
bucket.object("example_01.txt").delete(version_id: "BcczH4ZRVunnKyBuzk3cBOQgrh1gtGpR")
=> #<struct Aws::S3::Types::DeleteObjectOutput delete_marker=nil, version_id="BcczH4ZRVunnKyBuzk3cBOQgrh1gtGpR", request_charged=nil>
マルチパートアップロード
bucket = resource.bucket("bucket-01")
# デフォルトだと15MBより大きければマルチパートアップロードになる
# しきい値を変えたい場合は、`multipart_threshold`オプションを与える
bucket.object("very_large_file.txt").upload_file("/path/to/very_large_file")
=> true
署名付きURL作成
bucket = resource.bucket("bucket-01")
# `:get`/`put`/`head`/`delete`が指定できる
# `expires_in`はデフォルト900秒
bucket.object("example_01.txt").presigned_url(:get, expires_in: 3600)
=> "https://bucket-01.s3.ap-northeast-1.amazonaws.com/example_0001?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-...