21

I am trying to generate a pre-signed url on my Rails server to send to the browser, so that the browser can upload to S3.

It seems like aws-sdk-s3 is the gem to use going forward. But unfortunately, I haven't come across documentation for the gem that would provide clarity. There seem to be a few different ways of doing so, and would appreciate any guidance on the difference in the following methods -

  1. Using Aws::S3::Presigner.new (https://github.com/aws/aws-sdk-ruby/blob/master/aws-sdk-core/lib/aws-sdk-core/s3/presigner.rb) but it doesn't seem to take in an object parameter or auth credentials.

  2. Using Aws::S3::Resource.new, but it seems like aws-sdk-resources is not going to be maintained. (https://aws.amazon.com/blogs/developer/upgrading-from-version-2-to-version-3-of-the-aws-sdk-for-ruby-2/)

  3. Using Aws::S3::Object.new and then calling the put method on that object.

  4. Using AWS::SigV4 directly.

I am wondering how they differ, and the implications of choosing one over the other? Any recommendations are much appreciated, especially with aws-sdk-s3.

Thank you!

geoboy
  • 1,172
  • 1
  • 11
  • 25
  • What's wrong with using the sdk to do the image upload for you? – strongjz Jun 25 '17 at 16:19
  • I am trying avoid the extra hop or complexity of first uploading the files to my server. – geoboy Jun 25 '17 at 16:21
  • 1
    Here's the function for it in the Ruby sdk. http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Presigner.html – strongjz Jun 25 '17 at 16:34
  • right, but then I see other docs using `Resource.new` and am not sure the implications of different ways to do this. Here is an example: https://www.ajostrow.me/articles/s3-client-uploads – geoboy Jun 25 '17 at 17:00
  • From the example you gave it just creating a new S3 client then uses a function to generate the url. Or you can call the Ruby class for the presigned url function and feed it a bucket name. – strongjz Jun 25 '17 at 17:08
  • The AWS sdk's serach four places for credentials if you don't specific them. http://docs.aws.amazon.com/sdkforruby/api/index.html#Configuration – strongjz Jun 25 '17 at 17:10

2 Answers2

18

So, thanks to the tips by @strognjz above, here is what worked for me using `aws-sdk-s3'.

require 'aws-sdk-s3'

#credentials below for the IAM user I am using
s3 = Aws::S3::Client.new(
  region:               'us-west-2', #or any other region
  access_key_id:        AWS_ACCESS_KEY_ID,
  secret_access_key:    AWS_SECRET_ACCESS_KEY
)

signer = Aws::S3::Presigner.new(client: s3)
url = signer.presigned_url(
  :put_object,
  bucket: S3_BUCKET_NAME,
  key: "${filename}-#{SecureRandom.uuid}"
)
halfer
  • 19,824
  • 17
  • 99
  • 186
geoboy
  • 1,172
  • 1
  • 11
  • 25
  • 1
    Getting error AuthorizationQueryParametersError X-Amz-Algorithm only supports "AWS4-HMAC-SHA256" 3C113212318E91FE NMKudxNE0q91Xm/rgqlNTwl7ZXGVvaOT0EeCZRmTkULuyh2BLiIDLXOwJ6soRm9TtqieCEh9ENc= – Ankur Tripathi Jan 15 '19 at 12:45
17

This will work using the aws-sdk-s3 gem

aws_client = Aws::S3::Client.new(
  region:               'us-west-2', #or any other region
  access_key_id:        AWS_ACCESS_KEY_ID,
  secret_access_key:    AWS_SECRET_ACCESS_KEY
)


s3 = Aws::S3::Resource.new(client: aws_client)
bucket = s3.bucket('bucket-name')
obj = bucket.object("${filename}-#{SecureRandom.uuid}")

url = obj.presigned_url(:put)

additional http verbs:

obj.presigned_url(:put)                              
obj.presigned_url(:head)                    
obj.presigned_url(:delete)
csebryam
  • 1,091
  • 11
  • 13
  • 3
    :get is also a method. For the full list, here's the documentation: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#presigned_url-instance_method – Matt Jul 08 '19 at 22:11