Ten problem przeszkadza mi od wielu godzin i nie mogę znaleźć rozwiązania.Przesyłanie wielu plików bezpośrednio do Amazon S3 przy użyciu Rails 3.2 i AJAX (niewysłane rozwiązania do przesyłania plików flash)
Mam aplikację rails 3.2, która umożliwia użytkownikom przesyłanie plików na konto Amazon S3 przy użyciu operatora carrierwave_direct, mgła i carrierwave (zależność od operatora carrierwave_direct). Za pomocą operatora carrierwave_direct użytkownik może pominąć przesłanie pliku na serwer, wysyłając go bezpośrednio do Amazon S3 (oszczędza przetwarzanie serwerów i limity czasowe, takie jak Heroku dla dużych plików).
Działa dobrze, jeśli wszystko, co musisz zrobić, to wybrać 1 plik, przesłać go do Amazon i chcieć przekierować na adres URL podany przez Amazon. Robi to, wysyłając formularz do Amazon S3, a Amazon odpowiada na podany adres URL (podajesz ten URL w formularzu) z kilkoma parametrami w adresie URL, które są następnie zapisywane jako wskaźnik do pliku na Amazon w twoim modelu.
Cykl życia to: wybierz 1 plik, POST do Amazon, Amazon odpowiada adresem URL, który przesyła cię na inną stronę, a następnie możesz zapisać rekord za pomocą wskaźnika do pliku Amazon.
Co starałem się dowiedzieć, w jaki sposób mogę zezwolić na wybieranie i wysyłanie wielu plików i aktualizowanie postępu przesyłania? Próbuję to zrobić z czystym javascript (przy użyciu pliku API udostępnianego przez nowoczesne przeglądarki), więc nie chcę żadnych zewnętrznych narzędzi. Ponadto, w pogoni za nauce tego dogłębnie, unikam jakichkolwiek wtyczek i próbuję napisać kod sam.
Funkcjonalność Próbuję uzyskać to:
- użytkownik widzi formularz z polem plik (lub drag/drop)
- użytkownik wybiera wielu plików (albo kliknij pole pliku lub przeciągnij/upuść)
- użyciu JavaScript (bez serwerów jeszcze), zbudować kolejkę wybranych plików do przesłania (tylko nazwę pliku i rozmiar, przy użyciu API przeglądarka plików)
- następnie użytkownik kliknie „prześlij rozpoczęciem” przycisk
- iteracyjne nad każdego pliku w kolejce na d POST plik do Amazon S3; Amazon odpowie na każdy POST adresem URL, a ten adres URL musi być obsługiwany przez JavaScript, a nie jako standardowe żądanie; adres URL podany przez Amazon utworzy rekord przechowujący wskaźnik do pliku Amazon; po utworzeniu rekordu kod przechodzi do następnego pliku w kolejce do momentu zakończenia.
W tym momencie mogłem nawet zrobić bez indywidualnego paska postępu; Byłbym szczęśliwy tylko po to, aby uzyskać wiele plików POSTed do Amazon S3 bez odświeżania strony.
Nie jestem stronniczy od żadnego z klejnotów. Obawiam się, że będę musiał napisać to, co chcę zrobić od zera, jeśli naprawdę chcę, żeby to było zrobione w określony sposób. Celem jest wielokrotne przesyłanie plików na konto Amazon S3 za pośrednictwem AJAX. Byłbym zachwycony nawet ogólnymi koncepcjami podejścia do problemu. Spędziłem wiele godzin na szukaniu go i po prostu nie znalazłem żadnych rozwiązań, które by zrobiły to, co chcę. Jakakolwiek pomoc w ogóle byłaby bardzo doceniana.
EDIT 2014-03-02
Raj pytanie, jak I wdrożone moje wielokrotne wysyłanie. To było tak długo, że nie pamiętam wszystkich "dlaczego" za tym, co zrobiłem (prawdopodobnie zły kod tak czy inaczej, ponieważ był to mój pierwszy raz), ale oto, co robiłem.
Przesyłany przeze mnie model był referencją, która zawiera powiązany obraz przechowywany w Amazon S3.Pozwoliło to użytkownikowi na wybranie wielu obrazów (myślę, że były to pliki PDF, które przekonwertowałem na obrazy) i przeciągnij/upuść je na ekranie. Podczas przesyłania wyświetlałem modal, który dawał użytkownikowi informację o tym, ile czasu zajmie.
Nie chcę udawać, że pamiętam, co robiłem w wielu tego typu sytuacjach, ale jeśli to pomaga, można z niego korzystać.
# Gemfile
# For client-side multiple uploads
gem "jquery-fileupload-rails"
# For file uploads and Amazon S3 storage
gem "rmagick"
gem "carrierwave"
gem "fog"
oto widok:
# app/views/testimonials/new.html.erb
<div id="main" class="padded">
<div class="center">
<div id="dropzone">
Click or Drop Files here to Upload
</div>
<%= form_for @testimonial do |f| %>
<div class="field">
<%= file_field_tag :image, multiple: true, name: "testimonial[image]", id: "testimonial_image" %>
</div>
<% end %>
</div>
</div>
<div id="mask"></div>
<div id="modal">
<h1>
Uploading <span id="global-upload-count">0</span> Files...
</h1>
<div id="global-progress">
<div id="global-progress-bar" style="width: 0%">
<div id="global-progress-percentage">0%</div>
</div>
</div>
<div id="global-processing">
<span class="spinner"></span> Processing...<span id="global-processing-count">0</span> sec
</div>
</div>
<script id="template-upload" type="text/x-tmpl">
<div class="upload">
{%=o.name%} ({%=o.readable_size%})
<div class="float-right percentage"></div>
<div class="progress"><div class="bar" style="width: 0%"></div></div>
</div>
</script>
I JS:
number_to_human_size = (bytes) ->
sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
i = parseInt(Math.floor(Math.log(bytes)/Math.log(1024)))
return Math.round(bytes/Math.pow(1024, i), 2) + ' ' + sizes[i]
dropzone_hover = (e) ->
e.preventDefault()
$(this).addClass("dropzone-hover")
dropzone_leave = (e) ->
e.preventDefault()
$(this).removeClass("dropzone-hover")
jQuery ->
global_count = 0
seconds_to_process = 0
processing_factor = 5 # seconds to convert/process each uploaded file
$("#testimonial_image").hide()
dropzone = $("#dropzone")
dropzone.bind "click", (e) ->
$("#testimonial_image").click()
dropzone.bind("dragover", dropzone_hover)
dropzone.bind("dragleave", dropzone_leave)
dropzone.bind("drop", dropzone_leave)
$("#new_testimonial").data("global-count", "0")
$("#new_testimonial").fileupload
dropZone: $("#dropzone")
maxFileSize: 5000000 # 5 MB
dataType: "script"
add: (e, data) ->
file = data.files[0]
file.readable_size = number_to_human_size(file.size)
data.context = $(tmpl("template-upload", file).trim())
$("#new_testimonial").append(data.context)
data.submit()
global_count += 1
progress: (e, data) ->
if data.context
progress = parseInt(data.loaded/data.total * 100, 10)
data.context.find(".bar").css("width", progress + "%")
data.context.find(".percentage").text(progress + "%")
submit: (e, data) ->
$("#mask").show()
$("#modal").center().show()
progressall: (e, data) ->
$("#global-upload-count").text(global_count)
global_progress = parseInt(data.loaded/data.total * 100, 10)
$("#global-progress-bar").css("width", global_progress + "%")
$("#global-progress-percentage").text(global_progress + "%")
if global_progress >= 100
seconds_to_process = global_count * processing_factor
$("#global-processing-count").text(seconds_to_process)
$("#global-processing").show()
timer = setInterval(->
seconds_to_process = seconds_to_process - 1
$("#global-processing-count").text(seconds_to_process)
if seconds_to_process == 0
clearInterval(timer)
global_count = 0
seconds_to_process = 0
$("#modal, #mask").hide(0)
, 1000)
referencje model:
class Testimonial < ActiveRecord::Base
mount_uploader :image, ImageUploader
def display_name
if name.blank?
return "Testimonial #{self.id}"
else
return name
end
end
end
Użyj tego: http://blueimp.github.com/jQuery-File-Upload/ – apneadiving
@apneadiving, który działał dokładnie tak, jak chciałem. Strona z wtyczkami miała kilka bardzo pomocnych przykładów, które wskazały mi właściwy kierunek i zaimplementowałem dokładnie to, czego chcę. Jeśli zamiast komentarza odpowiesz na pytanie, chętnie przyjmuję twoją odpowiedź. Dziękuję bardzo, pomógł mi zaoszczędzić wiele wysiłku. –
Miło przeczytać :) – apneadiving