2

I have such view (form partial):

= javascript_include_tag 'car_photos'
= stylesheet_link_tag('jquery.fileupload-ui')
= form_for @car do |f|
  - if @car.errors.any?
    #error_explanation
      %h2= "О�?ибки в полях: #{pluralize(@car.errors.count, "error")}"
      %ul
        - @car.errors.full_messages.each do |msg|
          %li= msg
  .tab#car-data{style: "height: 1290px;"}
    .field
      = f.label :manufacturer_id, "Марка"
      = f.select(:manufacturer_id, options_from_collection_for_select(VehicleManufacturer.all, :id, :name, @car.manufacturer_id), {}, :prompt => "Выберите марк�?", required: true, id: "manufacturer-select")
    .field
      = f.label :model_id, "Модель"
      #models-area
        = render :partial => 'models', :object => @models
    .actions
      = link_to 'Перейти к загр�?зке фотографий', "", id: "go-and-load-photos", remote: true
  .tab#car-photo{style: "height: 1290px;"}
    .actions
      = link_to 'Назад к опи�?анию', "", id: "go-and-load-car-data", remote: true
  .actions
    = f.submit 'Добавить', id: "submit-car"
.car-photo
  = form_for CarPhoto.new, :html => { :multipart => true, :id => "fileupload", remote: true  } do |f|
    .row.fileupload-buttonbar
      %span.fileinput-button
        %span Добавить файлы
        = f.file_field :car_photo, multiple: true
        = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
      %button.btn.btn-primary.start{type: "submit", remote: true}
        %span Загр�?зить
      %button.btn.btn-warning.cancel{type: "reset", remote: true}
        %span Отменить загр�?зк�?
      %button.btn.btn-danger.delete{type: "button", remote: true}
        %span Удалить
      %input.toggle{type: "checkbox"}/
    %table.table.table-striped
      %tbody.files{"data-target" => "#modal-gallery", "data-toggle" => "modal-gallery"}
:javascript
  var fileUploadErrors = {
      maxFileSize: 'Размер файла �?ли�?ком велик',
      minFileSize: 'Размер файла �?ли�?ком мал',
      acceptFileTypes: 'Ра�?�?ирение файла не поддерживает�?я',
      maxNumberOfFiles: 'Превы�?ен лимит файлов',
      uploadedBytes: 'Uploaded bytes exceed file size',
      emptyResult: 'Файл не был загр�?жен'
  };
/ The template to display files available for upload
%script#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>
  </td>
  <td class="start">{% if (!o.options.autoUpload) { %}
  <button class="btn btn-primary">
  <span>Загр�?зить</span>
  </button>
  {% } %}</td>
  {% } else { %}
  <td colspan="2"></td>
  {% } %}
  <td class="cancel">{% if (!i) { %}
  <button class="btn btn-warning">
  <span>Отменить загр�?зк�?</span>
  </button>
  {% } %}</td>
  </tr>
  {% } %}
/ The template to display files available for download
%script#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%}">
  <span>Удалить</span>
  </button>
  <input type="checkbox" name="delete" value="1">
  </td>
  </tr>
  {% } %}
%script{charset: "utf-8", type: "text/javascript"}
  $(function () {
  \// Initialize the jQuery File Upload widget:
  $('#fileupload').fileupload();
  \//
  \// Load existing files:
  $.getJSON($('#fileupload').prop('action'), function (files) {
  var fu = $('#fileupload').data('fileupload'),
  template;
  fu._adjustMaxNumberOfFiles(-files.length);
  console.log(files);
  template = fu._renderDownload(files)
  \.appendTo($('#fileupload .files'));
  \// Force reflow:
  fu._reflow = fu._transition && template.length &&
  template[0].offsetWidth;
  template.addClass('in');
  $('#loading').remove();
  });

  });

As you can see i try to upload multiple images, controller is such:

class CarPhotosController < ApplicationController
  before_action :set_car_photo, only: [:show, :edit, :update, :destroy]

  def new
    @car_photo = CarPhoto.new
  end

  def create 
    #binding.pry
    @car_photo = CarPhoto.new(car_photo: car_photo_params[:car_photo].first) 
    #binding.pry
    #@car_photo.user_id = current_user.id
    respond_to do |format| 
      if @car_photo.save #&& user_signed_in?
        format.html { redirect_to @car_photo, notice: 'Photo was successfully created.' } 
        format.json { data = {id: @car_photo.id, thumb: view_context.image_tag(@car_photo.car_photo.url(:thumb))} 
        render json: data, status: :created, location: @car_photo } 
      else 
        format.html { render action: "new" } 
        format.json { render json: @car_photo.errors, status: :unprocessable_entity } 
      end 
    end 
  end

  private
  # Use callbacks to share common setup or constraints between actions.
  def set_car_photo
    @car_photo = CarPhoto.find(params[:id])
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def car_photo_params
    params.require(:car_photo).permit(:car_photo, {:car_photo => []})
  end
end

and when i submit some image in chrome log i see, that server return such json:

{"id":31,"thumb":"\u003Cimg alt=\"1\" src=\"/system/car_photos/car_photos/000/000/031/thumb/1.jpg?1394785415\" /\u003E"}

and in db i see that it is saved, but why in view i get :

Error Empty file upload result  

what i do wrong? and how to solve it?

1 Answer 1

7

jquery-file-upload library requires JSON response in specific format: https://github.com/blueimp/jQuery-File-Upload/wiki/JSON-Response

This might be the problem.

By the way, please don't send response the way you do, I mean, don't call view methods in your controller. Either send just the url in response and add <img> tag in fileUpload callback or render it in view (using for example jbuilder gem)

Sign up to request clarification or add additional context in comments.

5 Comments

"By the way, please don't send response the way you do, I mean, don't call view methods in your controller. Either send just the url in response and add <img> tag in fileUpload callback or render it in view (using for example jbuilder gem) " didn't understand you, maybe give some code )
Sure. In your controller you have something like this: format.json { data = {id: @car_photo.id, thumb: view_context.image_tag(@car_photo.car_photo.url(:thumb)) This is bad practice. image_tag method belongs to view and should not be used in controller, you're mixing responsibilities here.
So the possible solution is to do either: format.json { data = {thumb: @car_photo.car_photo.url(:thumb)} } and later handling it in Javascript on frontend or just format.json and having file like car_photos/create.json.jbuilder where you put the view information. Actually combining these 2 would be the best option: use view file and put there just url, not <img> tag, add <img> later in Javascript. Let me know if it's still unclear
Depends what gem you use. If you use jbuilder it can looke like this: gist.github.com/arnvald/9546557
yes, it work's, great answer. ps: uwielbiam Polskę :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.