Реализовать загрузку каталогов с загрузкой файлов в формате jQuery и Rails

Я пытаюсь реализовать загрузку каталогов с помощью jQuery File Upload plugin от Blueimp. Rails 4 - мой бэкэнд, а для вложений я использую Carrierwave.

Проблема в том, что плагин jquery не может распознать папку, которую я загружаю. У меня уже есть параметр webkitdirectory, переданный в поле ввода. Может кто-нибудь помочь мне с этим?

Спасибо заранее.

Здесь код загрузки файла jQuery в application.js:

$('#fileupload').fileupload({
    dataType: "script",
    sequentialUploads: true,
    // This function is called when a file is added to the queue;
    // either via the browse button, or via drag/drop:
    add: function(e, data) {
        data.context = $(tmpl("template-upload", data.files[
                0]))
        data.context.addClass('working');
        //$('.upload-status-box').addClass('working');
        $('#Upload-Bar').append(data.context);
        $('.upload-status-box').show();
        // Listen for clicks on the cancel button
        data.context.find('span.cancel-upload').click(
            function() {
                jqXHR.abort();
                data.context.fadeOut(function() {
                    data.context.remove();
                });
                count = count - 1;
                removeUploadStatusBoxOnCompletion();
            });
        var jqXHR = data.submit();
        count = count + 1;
    },
    progress: function(e, data) {
        if (data.context) {
            $('.upload-status-box').show();
            progress = parseInt((data.loaded / data.total) *
                100);
            var uploadMeta = parseInt(data.loaded / 1000000) +
                "/" + parseInt(data.total / 1000000) +
                " MB - " + progress + "%";
            data.context.find('.progress-bar').css('width',
                progress + '%');
            data.context.find('.status').text(uploadMeta);
        }
    },
    done: function(e, data) {
        console.log(
            'Your files have been uploaded successfully!'
        );
        // alert('Your files have been uploaded successfully! Depending on the file size, you might have to wait for a while before performing any actions.');
        count = count - 1;
        data.context.removeClass('working');
        data.context.find('button.cancel-upload').hide();
        removeUploadStatusBoxOnCompletion();
    }
});

И вот мое поле ввода:

<div class="awesome-file-uploads" id="inline-upload-status">
<%= form_for [myfolder, Myfile.new], html: { multipart: true, :id => "fileupload" } do |f| %>
    <%= f.file_field :attachment, multiple: true, id: "fileinput", style: "display:none;", "webkitdirectory"=> "", "directory"=> "" %>
    <%= f.hidden_field :myfolder_parent_id, value: myfolder.id %>
<% end %>

Здесь приведен код для загрузки и обработки файлов внутри папки:

    $('#folderupload').change(function(e) {
    e.preventDefault();
    NProgress.done();
    var items = e.target.files;
    var paths = ""; //
    // var myfolder_id = $(this).parent();
    for (var i=0, file; file=items[i]; i++) { 
    paths += file.webkitRelativePath+"###";
    } //
    // uploadFiles(items, myfolder_id.data('inside'));
    $("#paths").val(paths);
    $("#folderupload").submit(); //
});
function uploadFiles(items, myfolder_id){
   xhr = new XMLHttpRequest();
    data = new FormData();
    paths = "";

    var AUTH_TOKEN = $('meta[name=csrf-token]').attr('content');
    data.append('authenticity_token', AUTH_TOKEN);

    // Set how to handle the response text from the server
    xhr.onreadystatechange = function(ev){
        console.debug(xhr.responseText);
    };

    for (var i=0, file; file=items[i]; i++) {
        paths += file.webkitRelativePath+"###";
        data.append(i, file);
    }

    data.append('paths', paths);

    xhr.open('POST', "/myfolders/"+myfolder_id+"/create_from_folder", true);
    xhr.send(this.data);
}

Ответ 1

Привет, очень простая в использовании загрузка файла blueimp в рельсах. Просто вы можете установить драгоценные камни для загрузки файла blueimp.Famous - это драгоценный камень Carrierwave и драгоценный камень Dragonfly. Если у вас есть один из этих драгоценных камней, вы можете использовать следующие шаги для работы с blueimp

Необходимые условия

have jQuery setup in your app

copy jQuery File Upload files in the proper directories of your Rails app

Модели Для использования с жемчужиной Carrierwave

Мы будем использовать базовый загрузчик Carrierwave:

class AvatarUploader < CarrierWave::Uploader::Base
  storage :file
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
end

Позвольте настроить модель изображения

class Picture < ActiveRecord::Base
  include Rails.application.routes.url_helpers
  mount_uploader :avatar, AvatarUploader

  #one convenient method to pass jq_upload the necessary information
  def to_jq_upload
    {
      "name" => read_attribute(:avatar),
      "size" => avatar.size,
      "url" => avatar.url,
      "thumbnail_url" => avatar.thumb.url,
      "delete_url" => picture_path(:id => id),
      "delete_type" => "DELETE" 
    }
  end
end

Для использования с жемчужиной Dragonfly

настройте модель изображения (убедитесь, что в вашей базе данных есть как аватары, так и имена аватаров)

class Picture < ActiveRecord::Base
  include Rails.application.routes.url_helpers
  image_accessor :avatar

  #one convenient method to pass jq_upload the necessary information
  def to_jq_upload
    {
      "name" => read_attribute(:avatar_name),
      "size" => avatar.size,
      "url" => avatar.url,
      "thumbnail_url" => avatar.thumb('80x80#').url,
      "delete_url" => picture_path(:id => id),
      "delete_type" => "DELETE" 
    }
  end
end

контроллер

Первый контроллер для обработки загрузок: (html-ответ для браузеров с использованием разрешения iframe)

class PicturesController < ApplicationController

  def index
    @pictures = Picture.all
    render :json => @pictures.collect { |p| p.to_jq_upload }.to_json
  end

  def create
    @picture = Picture.new(params[:picture])
    if @picture.save
      respond_to do |format|
        format.html {  
          render :json => [@picture.to_jq_upload].to_json, 
          :content_type => 'text/html',
          :layout => false
        }
        format.json {  
          render :json => [@picture.to_jq_upload].to_json           
        }
      end
    else 
      render :json => [{:error => "custom_failure"}], :status => 304
    end
  end

  def destroy
    @picture = Picture.find(params[:id])
    @picture.destroy
    render :json => true
  end
end

И он маршрутизирует:

resources: pictures,: only = > [: index,: create,: destroy]

Разрешить воспроизведение

В любом файле просмотра, скопируйте этот код и наслаждайтесь.

<h2><%= t('photos.title') %></h2>
<%= form_for Picture.new, :html => { :multipart => true, :id => "fileupload"  } do |f| %>
        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
        <div class="row fileupload-buttonbar">
            <div class="span7">
                <!-- The fileinput-button span is used to style the file input field as button -->
                <span class="btn btn-success fileinput-button">
                    <i class="icon-plus icon-white"></i>
                    <span>Add files...</span>
                    <%= f.file_field :avatar %>
                </span>
                <button type="submit" class="btn btn-primary start">
                    <i class="icon-upload icon-white"></i>
                    <span>Start upload</span>
                </button>
                <button type="reset" class="btn btn-warning cancel">
                    <i class="icon-ban-circle icon-white"></i>
                    <span>Cancel upload</span>
                </button>
                <button type="button" class="btn btn-danger delete">
                    <i class="icon-trash icon-white"></i>
                    <span>Delete</span>
                </button>
                <input type="checkbox" class="toggle">
            </div>
            <div class="span5">
                <!-- The global progress bar -->
                <div class="progress progress-success progress-striped active fade">
                    <div class="bar" style="width:0%;"></div>
                </div>
            </div>
        </div>
        <!-- The loading indicator is shown during image processing -->
        <div class="fileupload-loading"></div>
        <br>
        <!-- The table listing the files available for upload/download -->
        <table class="table table-striped"><tbody class="files" data-toggle="modal-gallery" data-target="#modal-gallery"></tbody>
        </table>
    <% end %>
<script>
  var fileUploadErrors = {
    maxFileSize: 'File is too big',
    minFileSize: 'File is too small',
    acceptFileTypes: 'Filetype not allowed',
    maxNumberOfFiles: 'Max number of files exceeded',
    uploadedBytes: 'Uploaded bytes exceed file size',
    emptyResult: 'Empty file upload result'
  };
</script>

<!-- The template to display files available for upload -->
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-upload fade">
        <td class="preview"><span class="fade"></span></td>
        <td class="name"><span>{%=file.name%}</span></td>
        <td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
        {% if (file.error) { %}
            <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
        {% } else if (o.files.valid && !i) { %}
            <td>
                <div class="progress progress-success progress-striped active"><div class="bar" style="width:0%;"></div></div>
            </td>
            <td class="start">{% if (!o.options.autoUpload) { %}
                <button class="btn btn-primary">
                    <i class="icon-upload icon-white"></i>
                    <span>{%=locale.fileupload.start%}</span>
                </button>
            {% } %}</td>
        {% } else { %}
            <td colspan="2"></td>
        {% } %}
        <td class="cancel">{% if (!i) { %}
            <button class="btn btn-warning">
                <i class="icon-ban-circle icon-white"></i>
                <span>{%=locale.fileupload.cancel%}</span>
            </button>
        {% } %}</td>
    </tr>
{% } %}
</script>
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-download fade">
        {% if (file.error) { %}
            <td></td>
            <td class="name"><span>{%=file.name%}</span></td>
            <td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
            <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
        {% } else { %}
            <td class="preview">{% if (file.thumbnail_url) { %}
                <a href="{%=file.url%}" title="{%=file.name%}" rel="gallery" download="{%=file.name%}"><img src="{%=file.thumbnail_url%}"></a>
            {% } %}</td>
            <td class="name">
                <a href="{%=file.url%}" title="{%=file.name%}" rel="{%=file.thumbnail_url&&'gallery'%}" download="{%=file.name%}">{%=file.name%}</a>
            </td>
            <td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
            <td colspan="2"></td>
        {% } %}
        <td class="delete">
            <button class="btn btn-danger" data-type="{%=file.delete_type%}" data-url="{%=file.delete_url%}">
                <i class="icon-trash icon-white"></i>
                <span>{%=locale.fileupload.destroy%}</span>
            </button>
            <input type="checkbox" name="delete" value="1">
        </td>
    </tr>
{% } %}
</script>



<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<%= javascript_include_tag 'jquery.ui.widget.js' %>
<!-- The Templates and Load Image plugins are included for the FileUpload user interface -->
<script src="https://blueimp.github.com/JavaScript-Templates/tmpl.min.js"></script>
<script src="https://blueimp.github.com/JavaScript-Load-Image/load-image.all.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<%= javascript_include_tag 'jquery.iframe-transport.js' %>
<%= javascript_include_tag 'jquery.fileupload.js' %>
<%= javascript_include_tag 'jquery.fileupload-ui.js' %>
<!-- add include_tag js files to config.assets.precompile in ...environments/production.rb if you have it in vendor/ assets -->

<script type="text/javascript" charset="utf-8">
    $(function () {
        // Initialize the jQuery File Upload widget:
        $('#fileupload').fileupload();
        // 
        // Load existing files:
        $.getJSON($('#fileupload').prop('action'), function (files) {
          var fu = $('#fileupload').data('blueimp-fileupload'), 
            template;
          fu._adjustMaxNumberOfFiles(-files.length);
          template = fu._renderDownload(files)
            .appendTo($('#fileupload .files'));
          // Force reflow:
          fu._reflow = fu._transition && template.length &&
            template[0].offsetWidth;
          template.addClass('in');
          $('#loading').remove();
        });

    });
</script>

Ответ 2

Использование загрузки файла jQuery (версия пользовательского интерфейса) с пользовательским обработчиком загрузки на стороне сервера

  • Внедрите обработчик переноса файлов на своей платформе (Ruby, Python, Java и т.д.), который обрабатывает загрузку файлов на основе обычной формы и загружает их на ваш сервер. См. Также учебники на стороне сервера на странице Домашняя страница документации.
  • Загрузить и извлечь архив плагина.
  • Измените main.js и настройте параметр url на URL-адрес вашего настраиваемого обработчика загрузки файлов. В качестве альтернативы вы можете удалить опцию url и отредактировать index.html и настроить атрибут действия элемента формы HTML на URL своего пользовательского обработчика загрузки файлов. Если вашему загрузчику требуется другое имя параметра для загрузки файлов, чем файлы [], вам также необходимо настроить атрибут имени ввода файла или установить параметр paramName (см. Документацию по параметрам).
  • Загрузите папку jQuery-File-Upload на свой веб-сайт.
  • Расширьте свой пользовательский обработчик загрузки на стороне сервера, чтобы вернуть ответ JSON, похожий на следующий вывод:

Вы можете увидеть формат вывода, перейдя в https://github.com/blueimp/jQuery-File-Upload/wiki/Setup