Я использую модифицированную версию Jquery Multi-file uploader из Railscast # 383 (http://railscasts.com/episodes/383-uploading-to-amazon-s3) в приложении Rails 3, и мне нужно настроить его так, чтобы он проверял, файл уже существует на S3 и пропускает повторную загрузку, если это так.Избегайте перезаписи файлов S3 с помощью Jquery-Fileupload
Некоторые предпосылки: моим пользователям необходимо обновить большие куски данных. Например, можно выбрать 500 файлов размером 4 МБ для загрузки. Неизбежно, их интернет-соединение ломается, и вместо того, чтобы ожидать, что пользователь выяснит, какие файлы загружены, а какие нет, я хочу, чтобы они могли просто выбрать те же 500 файлов, и приложение было достаточно умным, чтобы не запускать снова на самое начало.
Наиболее предпочтительным решением было бы включить опцию в S3 POST, которая говорит, что не перезаписывать существующий файл. Следующим наиболее предпочтительным было бы отключить GET до S3, чтобы увидеть, существует ли файл и пропустить его, если это так.
Наименее предпочтительно, что я реализовал решение, которое не асинхронно запускает GET в мое приложение Rails (поскольку я создаю запись базы данных после завершения каждой загрузки), но у меня, похоже, возникают проблемы с дросселированием этих запросов , и мой пользователь говорит, что ее браузер продолжает терпеть крах (это все 500 одновременно, я думаю).
Соответствующие application.js
//= require jquery
//= require jquery_ujs
//= require jquery.ui.all
//= require jquery-fileupload/basic
//= require jquery-fileupload/vendor/tmpl
Моя форма:
<%= s3_uploader_form post: uploaded_photos_path, as: "uploaded_photo[image_url]", photo_shoot_id: @photo_shoot.id do %>
<%= file_field_tag :file, multiple: true %>
<%= button_tag 'Upload Photos', id: 'upload_photo_button', type: 'button' %>
<% end %>
Моя JavaScript:
$(function() {
$('#s3_uploader').fileupload({
limitConcurrentUploads: 5,
add: function(e, data) {
var file, record_exists, photo_check_url;
file = data.files[0];
photo_check_url = "/my_route/has_photo_been_uploaded/" + encodeURIComponent(file.name)
// THIS IS MY NON-THROTTLING HACK THAT NEEDS REPLACEMENT/IMPROVEMENT
// THE CONTROLLER THAT HANDLES THE REQUEST JUST RENDERS AN INLINE STRING OF 'true' OR 'false'
$.ajax({
url: photo_check_url,
async: false,
success: function (result) {
record_exists = result;
}
});
if (record_exists == 'false') {
data.context = $(tmpl("template-upload", file));
$('#s3_uploader').append(data.context);
data.submit();
}
},
progress: function(e, data) { // irrelevant },
done: function(e, data) { // irrelevant. It posts the object to my database }
},
fail: function(e, data) { // irrelevant }
});
});
Мой Helper:
module S3UploaderHelper
def s3_uploader_form(options = {}, &block)
uploader = S3Uploader.new(options)
form_tag(uploader.url, uploader.form_options) do
uploader.fields.map do |name, value|
hidden_field_tag(name, value)
end.join.html_safe + capture(&block)
end
end
class S3Uploader
def initialize(options)
@options = options.reverse_merge(
id: "s3_uploader",
aws_access_key_id: ENV["S3_ACCESS_KEY"],
aws_secret_access_key: ENV["S3_SECRET_ACCESS_KEY"],
bucket: S3_BUCKET_NAME,
acl: "private",
expiration: 10.hours.from_now.utc,
max_file_size: 20.megabytes,
as: "file"
)
end
def form_options
{
id: @options[:id],
method: "post",
authenticity_token: false,
multipart: true,
data: {
post: @options[:post],
as: @options[:as]
}
}
end
def fields
{
:key => key,
:acl => @options[:acl],
:policy => policy,
:signature => signature,
"AWSAccessKeyId" => @options[:aws_access_key_id],
}
end
def key
@key ||= "uploaded_photos/${filename}"
end
def url
"https://#{@options[:bucket]}.s3.amazonaws.com/"
end
def policy
Base64.encode64(policy_data.to_json).gsub("\n", "")
end
def policy_data
{
expiration: @options[:expiration],
conditions: [
["starts-with", "$utf8", ""],
["starts-with", "$key", ""],
["content-length-range", 0, @options[:max_file_size]],
{bucket: @options[:bucket]},
{acl: @options[:acl]}
]
}
end
def signature
Base64.encode64(
OpenSSL::HMAC.digest(
OpenSSL::Digest::Digest.new('sha1'),
@options[:aws_secret_access_key], policy
)
).gsub("\n", "")
end
end
end
Или если есть способ дросселировать запуск события ADD, это тоже сработает для меня. – LikeMaBell
Возможно, я асинхронно звоню в свою базу данных и добавляю крючок, который следит за «ложным» ответом, а затем запускает отправку (POST на S3)? Какие-нибудь советы о том, как будет выглядеть этот код? – LikeMaBell