30

I've been using this forever with paperclip and aws-s3:

  def authenticated_url(style = nil, expires_in = 90.minutes)
      AWS::S3::S3Object.url_for(attachment.path(style || attachment.default_style), attachment.bucket_name, :expires_in => expires_in, :use_ssl => true)
  end

The new paperclip uses the AWS-SDK gem, which breaks this giving the error:

undefined method `url_for' for AWS::S3:Class

Anyone know how to get this method to work with the new AWS-SDK gem?

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012

5 Answers5

30

To generate a url using the aws-sdk gem you should use the AWS::S3Object#url_for method.
You can access the S3Object instance from a paperclip attachment using #s3_object. The snippet below should resolve your issue.

def authenticated_url(style = nil, expires_in = 90.minutes)
  attachment.s3_object(style).url_for(:read, :secure => true, :expires => expires_in).to_s
end
Trevor Rowe
  • 6,499
  • 2
  • 27
  • 35
  • S3Object#url_for returns a URI::HTTPS object. If you prefer this you can omit the #to_s from the method chain. – Trevor Rowe Feb 09 '12 at 22:38
  • AWS::S3::Base is a class inside the old aws-s3 gem, but it does not exist as part of the aws-sdk gem. Both gems define the class AWS::S3 though. I'd dig through the stack trace and find out what is referencing AWS::S3::Base. – Trevor Rowe Feb 13 '12 at 22:28
15

Recently I upgraded to the newest gem for AWS SDK 2 for Ruby (aws-sdk-2.1.13) and getting pre-signed url has changed in this SDK version.

The way of getting it:

presigner = Aws::S3::Presigner.new
presigner.presigned_url(:get_object, #method
                        bucket: 'bucket-name', #name of the bucket
                        key: "key-name", #key name
                        expires_in: 7.days.to_i #time should be in seconds
                        ).to_s

You can find more info here: http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Presigner.html

Viktor Nonov
  • 1,472
  • 1
  • 12
  • 26
  • 2
    I found that an Aws::S3::ObjectSummary responds to `presigned_url` as well, and I didn't need an Aws::S3::Presigner object. The details in the comments are gold, though, thanks! – pdobb Aug 09 '16 at 20:25
5

After looking into the documentation, url_for is an instance method and not a class method.

To generate a URL with aws-sdk, you need to do the following:

bucket = AWS::S3::Bucket.new(attachment.bucket_name)
s3object = AWS::S3::S3Object.new(bucket, attachment.path(style || attachment.default_style))
s3object.url_for(:read, :expires => expires_in)

The options are slightly different than the ones you specified.

Options Hash (options):

:expires (Object) — Sets the expiration time of the URL; after this time S3 will return an error if the URL is used. This can be an integer (to specify the number of seconds after the current time), a string (which is parsed as a date using Time#parse), a Time, or a DateTime object. This option defaults to one hour after the current time.

:secure (String) — Whether to generate a secure (HTTPS) URL or a plain HTTP url.

:response_content_type (String) — Sets the Content-Type header of the response when performing an HTTP GET on the returned URL.

:response_content_language (String) — Sets the Content-Language header of the response when performing an HTTP GET on the returned URL.

:response_expires (String) — Sets the Expires header of the response when performing an HTTP GET on the returned URL.

:response_cache_control (String) — Sets the Cache-Control header of the response when performing an HTTP GET on the returned URL.

:response_content_disposition (String) — Sets the Content-Disposition header of the response when performing an HTTP GET on the returned URL.

:response_content_encoding (String) — Sets the Content-Encoding header of the response when performing an HTTP GET on the returned URL.

Gazler
  • 83,029
  • 18
  • 279
  • 245
  • "edit in the commits"? So how should I generate a url with the aws-sdk gem? – AnApprentice Feb 06 '12 at 20:28
  • @AnApprentice See my edit. Also, what version of the gem did your method work for? – Gazler Feb 06 '12 at 20:35
  • @AnApprentice I have editted again to reflect your sample code. – Gazler Feb 06 '12 at 20:46
  • Constructing the bucket and object in that manor relies on the global/default AWS.config values. It does not account for the configuration that might have been set directly on the attachment (e.g. credentials, region, use_ssl, retires, etc). – Trevor Rowe Feb 10 '12 at 17:14
3

I recently made the switch from aws-s3 to aws-sdk as well. I replaced all my url_for with the following:

 def authenticated_url(style = nil, expires_in = 90.minutes)
   self.attachment.expiring_url(expires_in, (style || attachment.default_style))
 end

You can see the discussion in the paperclip issues thread here: https://github.com/thoughtbot/paperclip/issues/732

John
  • 4,362
  • 5
  • 32
  • 50
  • Look at the method definition here: https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/storage/s3.rb. It is the same as your accepted answer. The only reason I could see it not working is if you do not have an s3.yml file with your access key and secret key or you are not specifying s3 in your paperclip options. What error are you getting? – John Feb 14 '12 at 05:09