2012-07-22 15 views
5

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:

  1. użytkownik widzi formularz z polem plik (lub drag/drop)
  2. użytkownik wybiera wielu plików (albo kliknij pole pliku lub przeciągnij/upuść)
  3. 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)
  4. następnie użytkownik kliknie „prześlij rozpoczęciem” przycisk
  5. 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 
+2

Użyj tego: http://blueimp.github.com/jQuery-File-Upload/ – apneadiving

+0

@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. –

+0

Miło przeczytać :) – apneadiving

Odpowiedz

6

Jak poinformowała w komentarzu, użyj jQuery Dodano: http://blueimp.github.com/jQuery-File-Upload/

+7

Chociaż może to teoretycznie odpowiedzieć na pytanie, [byłoby lepiej] (http://meta.stackexchange.com/q/8259), aby uwzględnić istotne części odpowiedzi tutaj, i podać link do odniesienia. –

+1

@IlmariKaronen Pisałem na prośbę pytającego. Ale nie krępuj się, jeśli chcesz – apneadiving

+0

Ktoś oznaczył twoją odpowiedź jako "nie jest odpowiedzią". Nie do końca się zgadzam, ale to * jest * dość graniczne. To powiedziawszy, pytanie też nie jest najczystsze. –

0

Zacząłem pisać bibliotekę podstawową dla tej funkcji. Mam działającą wersję na github i piszę serię postów na blogu, aby szczegółowo opisać, jak to osiągnąć.

Kod "Working" znajduje się pod adresem: https://github.com/joeandrews/s3multipartupload.

Powiązane problemy