5

이 문제는 여러 시간 동안 저를 괴롭 혔으며 해결 방법을 찾지 못하는 것 같습니다.레일즈 3.2 및 AJAX (플래시 이외의 업로드 솔루션)를 사용하여 여러 파일을 Amazon S3에 직접 업로드

저는 사용자가 carrierwave_direct, fog 및 carrierwave (carrierwave_direct에 대한 종속성)를 사용하여 Amazon S3 계정에 파일을 업로드 할 수있는 3.2 레일 앱이 있습니다. carrierwave_direct를 사용하면 Amazon S3에 직접 게시하여 서버로 파일 업로드를 건너 뛸 수 있습니다 (대용량 파일의 경우 Heroku와 같은 서버 처리 및 시간 초과가 저장됩니다).

1 개의 파일을 선택하고 Amazon으로 업로드 한 다음 Amazon에 제공 한 URL로 redirect_를 보내고 싶다면 잘 작동합니다. Amazon S3에 양식을 게시하면 Amazon이 양식에이 URL을 지정한 URL에 응답하고 모델의 Amazon에있는 파일에 대한 포인터로 저장됩니다.

수명주기는 다음과 같습니다. 파일 1 개 선택, Amazon에서 POST, Amazon에서 사용자를 다른 페이지로 보내는 URL로 응답 한 다음 Amazon 파일 포인터로 레코드를 저장할 수 있습니다.

여러 파일을 선택하고 업로드하고 업로드 진행률을 업데이트하는 방법은 무엇입니까? 나는 현대적인 브라우저에서 제공하는 파일 API를 사용하여 순수한 자바 스크립트로이 작업을 시도하고 있으므로 타사 도구가 필요하지 않습니다. 또한 깊이있는 학습을 위해 모든 플러그인을 피하고 직접 코드를 작성하려고합니다.

내가 얻기 위해 노력하고있어 기능은 다음과 같습니다

  1. 사용자는 파일 필드 (또는 드래그/드롭)
  2. 사용자가 여러 파일을 선택하여 양식을보고 (중 파일 필드 또는 드래그/드롭 클릭)
  3. 을 큐에있는 각 파일을 통해 자바 스크립트 (아무 서버 아직), 업로드
  4. 사용자가 다음 "시작 업로드"를 클릭 (단지 브라우저 파일 API를 사용하여 파일 이름과 크기)을 선택한 파일의 큐를 구축 버튼
  5. 으로 반복 사용
  6. ~ d 파일을 Amazon S3에 POST합니다. Amazon은 각 POST에 URL을 사용하여 응답하며 URL은 표준 요청이 아닌 Javascript를 통해 처리해야합니다. Amazon에서 제공 한 URL은 Amazon 파일에 대한 포인터를 저장하는 레코드를 생성합니다. 일단 레코드가 생성되면 코드는 완료 될 때까지 대기열의 다음 파일로 이동합니다.

이 시점에서 개별 진행 막대를 사용하지 않고도 할 수 있습니다. 페이지를 새로 고치지 않고 Amazon S3에 여러 파일을 게시하면됩니다.

나는 보석에 부분적이지 않다. 나는 실제로 그것이 특정한 방법으로 끝나기를 원한다면 내가하고 싶은 일을 처음부터 다시 써야 할 것 같아 두려워합니다. 목표는 AJAX를 통해 Amazon S3 계정에 여러 파일을 업로드하는 것입니다. 문제에 접근하는 일반적인 개념조차도 나는 황홀 할 것이다. 나는 많은 시간을 인터넷 검색을 통해 보냈으며, 나는 내가 원하는 것을 해결할만한 해결책을 찾지 못했다. 어떤 도움이라도 대단히 감사하겠습니다.

편집 2014년 3월 2일

주권은 내가 여러 업로드를 구현하는 방법을 물었다. 너무 오랫동안 나는 왜 내가했던 일 (아마도 어쨌든 처음에는 그랬듯이 나쁜 코드 일 것임) 뒤에 모든 "왜"를 떠 올리지 못했지만, 여기에 내가 무엇을했는지가 여기에있다.

내가 업로드 한 모델은 회원 이미지이며 Amazon S3에 저장된 이미지입니다.그것은 사용자가 여러 이미지를 선택할 수있게 해주었습니다. 실제로 이미지로 변환 한 PDF 파일이라고 생각하고 화면에 드래그/드롭합니다. 업로드하는 동안 사용자에게 얼마나 오래 걸릴지에 대한 피드백을 제공하는 모달을 표시했습니다.

나는이 일을 많이 기억하지 못하지만, 그것을 자유롭게 사용하면 도움이된다.

# 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> 

그리고 JS : 여기

# Gemfile 
# For client-side multiple uploads 
gem "jquery-fileupload-rails" 

# For file uploads and Amazon S3 storage 
gem "rmagick" 
gem "carrierwave" 
gem "fog" 

뷰의

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) 

증언에 모델 :

코멘트에 조언으로
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

다음을 사용하십시오. http://blueimp.github.com/jQuery-File-Upload/ – apneadiving

+0

@apneadiving은 내가 원했던대로 정확하게 작동했습니다. 플러그인 페이지에는 올바른 방향으로 나를 가리키는 유용한 예제가 있었으며 원하는대로 구현했습니다. 의견 대신 질문에 대한 답변을 작성하면 기꺼이 답변을 수락합니다. 대단히 고마워, 너는 내게 많은 노력을 덜어 줬다. –

+0

니스 : – apneadiving

답변

6

이 사용 jQuery를 업로드 : http://blueimp.github.com/jQuery-File-Upload/

+7

이것은 이론적으로 질문에 대답 할 수 있지만 여기에 대답의 핵심 부분을 포함하고 참조 용 링크를 제공하는 것이 바람직합니다 (http://meta.stackexchange.com/q/8259). –

+1

@IlmariKaronen 나는 asker 요청시 게시했습니다. 그러나 당신이 좋아하는 경우에 downvote에 자유롭게 느끼십시오 – apneadiving

+0

누군가는 당신의 응답을 "대답 아닙니다"표시했다. 나는 정말로 동의하지 않는다. 그러나 it *는 꽤 경계 다. 즉, 질문은 정확히 어느 것이 든 가장 명확한 질문이 아닙니다. –

0

이 기능을위한 기본 라이브러리를 작성하기 시작했습니다. 나는 github에 대한 작업 버전을 보유하고 있으며이를 달성하는 방법을 자세하게 설명하는 일련의 블로그 게시물을 작성하고 있습니다.

'Working'코드는 https://github.com/joeandrews/s3multipartupload에서 찾을 수 있습니다.

관련 문제