Почему я получил Uncaught TypeError: fileInput.fileupload не является функцией, использующей Ruby on Rails и JQuery? - PullRequest
0 голосов
/ 29 октября 2018

Я следовал за «Прямая загрузка изображений S3 в Rails» . Моя цель - загрузить документы непосредственно в Amazon S3 через форму и сохранить соответствующую ссылку s3 в модель UserDocument.

Я использую ruby ​​2.2.10p489 и Rails 5.1.6. Я пытаюсь загрузить файлы напрямую в Amazon S3 с помощью JQuery. При загрузке представления new.html.erb в консоли JavaScript Chrome появляется следующее сообщение об ошибке:

Uncaught TypeError: fileInput.fileupload is not a function
    at HTMLInputElement.<anonymous> (client_side_s3_upload.self-2be7ed022d6f0781280d316c208a0c078031b2d12aee201b25082ec22be186e6.js:10)
    at Function.each (jquery-3.3.1.self-5af507e253c37e9c9dcf65064fc3f93795e6e28012780579975a4d709f4074ad.js:355)
    at jQuery.fn.init.each (jquery-3.3.1.self-5af507e253c37e9c9dcf65064fc3f93795e6e28012780579975a4d709f4074ad.js:190)
    at HTMLDocument.<anonymous> (client_side_s3_upload.self-2be7ed022d6f0781280d316c208a0c078031b2d12aee201b25082ec22be186e6.js:3)
    at fire (jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:3233)
    at Object.fireWith [as resolveWith] (jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:3363)
    at Function.ready (jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:3583)
    at HTMLDocument.completed (jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js:3618)

Вот представление new.html.erb, относящееся к форме загрузки:

<%= javascript_include_tag 'jquery-3.3.1.js' %>
<%= javascript_include_tag 'jquery.ui.widget.js' %>
<%= javascript_include_tag 'z.jquery.fileupload.js' %>

<% if !@user_document.errors.empty? %>
   <div class = "alert alert-error">

      <ul>
         <% @user_document.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
         <% end %>
      </ul>

   </div>

 <% end %>

<div class = "well">

   <%= form_for(@user_document, html: { class: 'directUpload', data: { 'form-data' => (@s3_direct_post.fields), 'url' => @s3_direct_post.url, 'host' => URI.parse(@s3_direct_post.url).host } }) do |f| %>
      <div class="field">
      <%= f.label :attachment %>
      <%= f.file_field :attachment %>
      <%= f.submit "Save", class: "btn btn-primary" %>
      </div>
   <% end %>
</div>

Вот мое application.html.erb:

<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag Ckeditor.cdn_url %>
    <script src="https://js.stripe.com/v3/"></script>


    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>  
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>


    <style type="text/css">
    .bs-example{
        margin: 20px;
        }
    </style>

    <!== [if lt IE 9]>
      <script src = "cdnjs.cloudfare.com/ajax/libs/html5shiv/r29/html5.min.js">    
      </script> 
    <![endif]-->



 </head>

  <body>
     <div class="container">
    <% flash.each do |message_type, message| %>
      <div class="alert alert-info alert-<%= message_type %>"><%= message %></div>
    <% end %>
    <%= yield %>
  </div>
  </body>
</html>

Here is the relevant controller:


  class UserDocumentsController < ApplicationController

     before_action :logged_in_user
     before_action :set_s3_direct_post, only: [:new, :edit, :create, :update]     



     def new
        @user_document = UserDocument.new
     end


     def create
        @user_document = UserDocument.new(user_document_params)

        if @user_document.save
           redirect_to user_documents_path, notice: "The document #{@user_document.name} has been uploaded."
        else
           render "new"
        end

     end

     def destroy
        @user_document = UserDocument.find(params[:id])
        @user_document.destroy
        redirect_to user_documents_path, notice:  "The document #{@user_document.name} has been deleted."
     end

     private
     def user_document_params
       params.require(:user_document).permit(:name, :attachment)
     end

     def set_s3_direct_post
       @s3_direct_post = S3_BUCKET.presigned_post(key: "uploads/#{SecureRandom.uuid}/${filename}", success_action_status: '201', acl: 'private')
     end

  end

Вот код JavaScript:

$(function() {
  $('.directUpload').find("input:file").each(function(i, elem) {
    var fileInput    = $(elem);
    var form         = $(fileInput.parents('form:first'));
    var submitButton = form.find('input[type="submit"]');
    var progressBar  = $("<div class='bar'></div>");
    var barContainer = $("<div class='progress'></div>").append(progressBar);
    fileInput.after(barContainer);
    fileInput.fileupload({
      fileInput:       fileInput,
      url:             form.data('url'),
      type:            'POST',
      autoUpload:       true,
      formData:         form.data('form-data'),
      paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
      dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
      replaceFileInput: false,
      progressall: function (e, data) {
        var progress = parseInt(data.loaded / data.total * 100, 10);
        progressBar.css('width', progress + '%')
      },
      start: function (e) {
        submitButton.prop('disabled', true);

        progressBar.
          css('background', 'green').
          css('display', 'block').
          css('width', '0%').
          text("Loading...");
      },
      done: function(e, data) {
        submitButton.prop('disabled', false);
        progressBar.text("Uploading done");

        // extract key and generate URL from response
        var key   = $(data.jqXHR.responseXML).find("Key").text();
        var url   = '//' + form.data('host') + '/' + key;

        // create hidden field
        var input = $("<input />", { type:'hidden', name: fileInput.attr('name'), value: url })
        form.append(input);
      },
      fail: function(e, data) {
        submitButton.prop('disabled', false);

        progressBar.
          css("background", "red").
          text("Failed");
      }
    });
  });
});

1 Ответ

0 голосов
/ 29 октября 2018

UPDATE:

Тебе действительно нужно учить jquery, если ты собираешься сделать что-нибудь из этой работы. У вас есть много точек возможного сбоя, поэтому постарайтесь прислушиваться к тому, что сообщают вам сообщения об ошибках. Есть несколько способов отладки сломанного JS

добавьте отладчик и зайдите в консоль, чтобы увидеть, какие у вас объекты и какие функции на них можно вызывать. Я бы начал здесь:

$('.directUpload').find("input:file").each(function(i, elem) {
  var fileInput    = $(elem);
  debugger;

Посмотрите, имеет ли fileInput определенную функцию fileUpload, если это так, продолжайте и двигайте отладчик построчно.

Без четкого понимания jquery вы будете бороться с этим. Не видя фактического представления в браузере, я ограничен тем, что могу помочь вам в отладке.

Первый ответ:

Возможно, это не тот ответ, который вам нужен, но вы не можете просто использовать вместо него https://github.com/carrierwaveuploader/carrierwave?

Но также избавьтесь от этого в контроллере приложений, так как у вас другая версия загрузки jquery с javascript_tag

избавьтесь от других вещей в application.html и поместите это. Для начальной загрузки требуется jquery, поэтому убедитесь, что jquery стоит первым

<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag Ckeditor.cdn_url %>
<%= javascript_include_tag "https://js.stripe.com/v3/" %>
<!--- it would be better if you move these to qpplication.js --->
<%= javascript_include_tag 'jquery-3.3.1.js' %>
<%= javascript_include_tag 'jquery.ui.widget.js' %>
<%= javascript_include_tag 'z.jquery.fileupload.js' %>
<%= javascript_include_tag 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js' %>
<%= stylesheet_link_tag 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' %>

избавься от всего этого

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>  
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

Вы не должны пытаться использовать 2 разные версии jquery в одном приложении. Могут быть проблемы конфликта версий между версией jquery и jQuery-File-Upload, который вы используете.

Стандарт рельсов предусматривает включение необходимых js-файлов в application.js и их хранение в папке vendor/assets или использование драгоценного камня для их включения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...