Skip to content

Instantly share code, notes, and snippets.

@mvasin
Created November 5, 2017 14:46
Show Gist options
  • Save mvasin/8af43b146814eafb32ed919fc017118b to your computer and use it in GitHub Desktop.
Save mvasin/8af43b146814eafb32ed919fc017118b to your computer and use it in GitHub Desktop.
The slimmest app possible for uploading files to S3 using Shrine gem
require 'roda'
require 'shrine'
require 'shrine/storage/s3'
S3_OPTIONS = {
access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'),
region: ENV.fetch('AWS_REGION'),
bucket: ENV.fetch('AWS_BUCKET')
}.freeze
Shrine.storages = {
cache: Shrine::Storage::S3.new(
prefix: 'cache', upload_options: { acl: 'private' }, **S3_OPTIONS
),
store: Shrine::Storage::S3.new(
prefix: 'store', upload_options: { acl: 'public-read' }, **S3_OPTIONS
)
}
Shrine.plugin :presign_endpoint
# :nodoc:
# rubocop:disable BlockLength
class App < Roda
plugin :public
route do |r|
r.public # serve static assets
r.root do
<<-'HEREDOC'
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.2/css/bootstrap.min.css" rel="stylesheet"></link>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.19.1/js/vendor/jquery.ui.widget.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.19.1/js/jquery.fileupload.min.js"></script>
<script>
$(function() {
$('[type=file]').fileupload({
add: function(e, data) {
data.progressBar = $(
'<div class="progress" style="width: 300px"><div class="progress-bar"></div></div>'
).insertAfter(".form-group");
var options = { filename: data.files[0].name.match(/[^\/\\]+$/)[0] };
$.getJSON('/presign', options, function(result) {
data.formData = result['fields'];
data.url = result['url'];
data.paramName = 'file';
data.submit();
});
},
progress: function(e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
var percentage = progress.toString() + '%';
data.progressBar.find(".progress-bar")
.css("width", percentage).html(percentage);
},
done: function(e, data) {
// data.progressBar.remove();
var file = {
// we have to remove the prefix part
id: data.formData.key.match(/^cache\/(.+)/)[1],
storage: 'cache',
metadata: {
size: data.files[0].size,
// IE returns full path
filename: data.files[0].name.match(/[^\/\\]+$/)[0],
mime_type: data.files[0].type
}
}
$('#hidden_file').val(JSON.stringify(file))
$('<br><p>Done!</p>').insertAfter('.progress')
}
});
});
</script>
</head>
<body>
<div class="container">
<div class="form-group">
<form method="post" enctype="multipart/form-data">
<input id="hidden_file" type="hidden" name="file">
<input id="file" type="file" name="file">
<input type="submit">
</form>
</div>
</div>
</body>
</html>
HEREDOC
end
r.post '' do
"The file #{r.params['file']} has been uploaded."
end
r.is 'presign' do
r.run Shrine.presign_endpoint(:cache)
end
end
end
run App.freeze.app
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment