This repository has been archived by the owner on May 25, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Upload directly to S3
alexpls edited this page May 9, 2014
·
14 revisions
Here is a rails-specific example of uploading directly to S3 using the newest version of the plugin.
It makes a lot of assumptions, but it will get you where you need to be!
Before starting, you'll need to make sure that you include at least these Javascripts from the File-Upload source:
- jquery.ui.widget
- jquery.iframe-transport
- jquery.fileupload
Ok, given you have a form like so:
%form#file_upload(action="https://YOURBUCKET.s3.amazonaws.com" method="post" enctype="multipart/form-data")
-# order is important!
-# also, the things that are not filled in right now *will* be filled in soon. See below.
%input{:type => :hidden, :name => :key}
%input{:type => :hidden, :name => "AWSAccessKeyId", :value => "YOUR_ACCESS_KEY"}
%input{:type => :hidden, :name => :acl, :value => :private}
%input{:type => :hidden, :name => :success_action_status, :value => "200"}
%input{:type => :hidden, :name => :policy}
%input{:type => :hidden, :name => :signature}
.fileupload-content
.fileupload-progress
.file-upload
%label.fileinput-button
%span Upload Document
%input{:type => :file, :name => :file}
..and you have javascript to respond to that form like so:
$(function() {
$('#file_upload').fileupload({
forceIframeTransport: true, // VERY IMPORTANT. you will get 405 Method Not Allowed if you don't add this.
autoUpload: true,
add: function (event, data) {
$.ajax({
url: "/documents",
type: 'POST',
dataType: 'json',
data: {doc: {title: data.files[0].name}},
async: false,
success: function(retdata) {
// after we created our document in rails, it is going to send back JSON of they key,
// policy, and signature. We will put these into our form before it gets submitted to amazon.
$('#file_upload').find('input[name=key]').val(retdata.key);
$('#file_upload').find('input[name=policy]').val(retdata.policy);
$('#file_upload').find('input[name=signature]').val(retdata.signature);
}
});
data.submit();
},
send: function(e, data) {
// show a loading spinner because now the form will be submitted to amazon,
// and the file will be directly uploaded there, via an iframe in the background.
$('#loading').show();
},
fail: function(e, data) {
console.log('fail');
console.log(data);
},
done: function (event, data) {
// here you can perform an ajax call to get your documents to display on the screen.
$('#your_documents').load("/documents?for_item=1234");
// hide the loading spinner that we turned on earlier.
$('#loading').hide();
},
});
});
and your controller looks something like this:
# create the document in rails, then send json back to our javascript to populate the form that will be
# going to amazon.
def create
@document = Document.create(params[:doc])
render :json => {
:policy => s3_upload_policy_document,
:signature => s3_upload_signature,
:key => @document.s3_key,
:success_action_redirect => document_upload_success_document_url(@document)
}
end
# just in case you need to do anything after the document gets uploaded to amazon.
# but since we are sending our docs via a hidden iframe, we don't need to show the user a
# thank-you page.
def s3_confirm
head :ok
end
private
# generate the policy document that amazon is expecting.
def s3_upload_policy_document
return @policy if @policy
ret = {"expiration" => 5.minutes.from_now.utc.xmlschema,
"conditions" => [
{"bucket" => YOUR_BUCKET_NAME},
["starts-with", "$key", @document.s3_key],
{"acl" => "private"},
{"success_action_status" => "200"},
["content-length-range", 0, 1048576]
]
}
@policy = Base64.encode64(ret.to_json).gsub(/\n/,'')
end
# sign our request by Base64 encoding the policy document.
def s3_upload_signature
signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), YOUR_SECRET_KEY, s3_upload_policy_document)).gsub("\n","")
end