× {{alert.msg}} Never ask again
Get notified about new tutorials RECEIVE NEW TUTORIALS

How to generate the Policy and Signature to upload files from an HTML form to Amazon S3 on Ruby

<p><span style="font-size:14px">File uploads can take a lot of time out of your webserver, in environments like Heroku where your requests get killed after 30 seconds it is impossible to receive file uploads that take more than that to get sent.</span></p><p><span style="font-size:14px">The solution is to upload directly to amazon s3 and then catch the resulting URL on a callback, that way the long wait for the file to upload takes place on Amazon, not on your Heroku Dynos... freeing up some resources for your app to serve more requests.</span></p><p><span style="font-size:14px">You can find documentation about how to set up a form to post directly to S3 here: <a href="https://aws.amazon.com/articles/1434">https://aws.amazon.com/articles/1434</a></span></p><p><span style="font-size:14px">There you'll see that the FORM should be something line this:</span></p><pre><code class="language-html">&lt;form action="https://s3-bucket.s3.amazonaws.com/" method="post" enctype="multipart/form-data"&gt; &lt;input type="hidden" name="key" value="uploads/${filename}"&gt; &lt;input type="hidden" name="AWSAccessKeyId" value="YOUR_AWS_ACCESS_KEY"&gt; &lt;input type="hidden" name="acl" value="private"&gt; &lt;input type="hidden" name="success_action_redirect" value="http://localhost/"&gt; &lt;input type="hidden" name="policy" value="YOUR_POLICY_DOCUMENT_BASE64_ENCODED"&gt; &lt;input type="hidden" name="signature" value="YOUR_CALCULATED_SIGNATURE"&gt; &lt;input type="hidden" name="Content-Type" value="image/jpeg"&gt; &lt;!-- Include any additional input fields here --&gt; File to upload to S3: &lt;input name="file" type="file"&gt; &lt;br&gt; &lt;input type="submit" value="Upload File to S3"&gt; &lt;/form&gt; </code></pre><p><span style="font-size:14px">However, getting the <strong>'policy' </strong>and <strong>'signature'</strong> generated can be tricky... here is my snippet in ruby to generate these values:</span></p><pre><code class="language-ruby">def get_s3_upload_key(folder_key) bucket = ENV["S3_BUCKET"] access_key = ENV["S3_ACCESS_KEY"] secret = ENV["S3_SECRET_ACCESS_KEY"] key = "#{folder_key}/" expiration = 5.minutes.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z') max_filesize = 2.megabytes acl = 'public-read' sas = '201' # Tells amazon to redirect after success instead of returning xml policy = Base64.encode64( "{'expiration': '#{expiration}', 'conditions': [ {'bucket': '#{bucket}'}, {'acl': '#{acl}'}, {'Content-Type': 'image/jpeg'}, {'Content-Disposition': 'attachment'}, {'Cache-Control': 'max-age=31536000'}, ['starts-with', '$key', '#{key}'], ['content-length-range', 1, #{max_filesize}] ]} ").gsub(/\n|\r/, '') signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), secret, policy)).gsub(/\n| |\r/, '') {:access_key =&gt; access_key, :key =&gt; key, :policy =&gt; policy, :signature =&gt; signature, :sas =&gt; sas, :bucket =&gt; bucket, :acl =&gt; acl, :expiration =&gt; expiration} end</code></pre><p>You can tweak things like the mime type and maximum file size according to your needs.</p><p>The "folder_key" param that the method receives is the name of the folder under which you will be upoading the file. I am using ENV vars for the Access Credentials and Bucket names, but you could modify that to use params as well.</p>
comments powered by Disqus