Search code examples
rubyamazon-s3storagefogpre-signed-url

Use Fog with Ruby to generate a Pre-signed URL to PUT a file in Amazon S3


I am using the Fog gem to generate presigned urls. I can do this successfully to get read access to the file. Here's what I do:

    fog_s3 = Fog::Storage.new({
          :provider                 => 'AWS',
          :aws_access_key_id        => key,
          :aws_secret_access_key    => secret
    })
    object_path = 'foo.wav' 
    expiry = Date.new(2014,2,1).to_time.to_i
    url = fog_s3.directories.new(:key => bucket).files.new(:key => object_path).url(expiry,path_style: true)

But this doesn't work when I try to upload the file. Is there a way to specify the http verb so it would be a PUT and not a GET?

EDIT I see a method: put_object_url which might help. I don't know how access it.

Thanks

EDIT based upon your suggestion:

It helped - it got me a PUT - not GET. However, I'm still having issues. I added content type:

    headers = { "Content-Type" => "audio/wav" }
    options = { path_style: true }
    object_path = 'foo.wav' 
    expiry = Date.new(2014,2,1).to_time.to_i  
    url = fog_s3.put_object_url(bucket,object_path, expiry, headers, options)

but the url does not contain Content-Type in it. When done from Javascript in HTML I get the Content-Type in the url and that seems to work. Is this an issue with Fog? or is my header incorrect?


Solution

  • I think put_object_url is indeed what you want. If you follow the url method back to where it is defined, you can see it uses a similar method underlying it called get_object_url here (https://github.com/fog/fog/blob/dc7c5e285a1a252031d3d1570cbf2289f7137ed0/lib/fog/aws/models/storage/files.rb#L83). You should be able to do something similar and can do so by calling this method from the fog_s3 object you already created above. It should end up just looking like this:

    headers = {}
    options = { path_style: true }
    url = fog_s3.put_object_url(bucket, object_path, expires, headers, options)
    

    Note that unlike get_object_url there is an extra headers option snuck in there (which you can use to do stuff like set Content-Type I believe).

    Hope that sorts it for you, but just let me know if you have further questions. Thanks!

    Addendum

    Hmm, seems there may be a bug related to this after all (I'm wondering now how much this portion of the code has been exercised). I think you should be able to work around it though (but I'm not certain). I suspect you can just duplicate the value in the options as a query param also. Could you try something like this?

    headers = query = { 'Content-Type' => 'audio/wav' }
    options = { path_style: true, query: query }
    url = fog_s3.put_object_url(bucket, object_path, expires, headers, options)
    

    Hopefully that fills in the blanks for you (and if so we can think some more about fixing that behavior within fog if it makes sense to do so). Thanks!