1

I'm working with jquery-file-upload-rails gem to upload multiple images with preview on my form. File upload is working, but the partial with new photos renders only after browser refresh! Maybe, someone can see, what is wrong.

I'm calling file uploader to load photo images in project's edit page:

= f.fields_for :photos, Photo.new do |ff|
  = ff.file_field :img_file, multiple: true, name: "project[photos_attributes][][img_file]", id: 'new_photo'

Photo controller:

  def create
    @project = Project.find(params[:project_id])
    @photo = @project.photos.create(params[:photo].permit(:img_file))
    respond_to do |format|
      format.js
      format.html
    end
  end

photos.js.coffee to make the jquery-file-uploader-rails gem working:

jQuery ->
  $('#new_photo').fileupload
    dataType: 'script'

create.js.erb

$('#photos').html("<%= j render(@photo) %>");

_photo.html.haml

.photo
  - @project.photos.each do |photo|
    = image_tag photo.img_file.thumb
    = link_to 'Remove', photo, data: { confirm: "Are you sure?" }, method: :delete

So I can upload photos. But my ajax doesn't work, even if I put only alert('help'); in my create.js.erb, it doesn't respond. What am I doing wrong? Many thanks in advance!

UPDATE Current situation (with help of Rich Peck):

My models:

class Project < ActiveRecord::Base
  has_many :photos, dependent: :destroy
  accepts_nested_attributes_for :photos, allow_destroy: true
end

class Photo < ActiveRecord::Base
  belongs_to :project
  validates :img_file, presence: true
  mount_uploader :img_file, ImageUploader
end

Projects controller:

  def edit
    @project = Project.find(params[:id])
    @project.photos.build
  end

  def update
    @project = Project.find(params[:id])
    @project.update(project_params)
  end

params.require(:project).permit(photos_attributes: [:img_file])

/projects/edit

  = form_for @project do |f|
    = f.fields_for :photos do |p|
      = p.file_field :img_file, multiple: true, id: 'new_photo'       
  #photos
    = render 'photos/photo'

/photos/_photo

.photo
  = image_tag photo.img_file.thumb if photo.img_file?
  = link_to 'Remove', photo, data: { confirm: "Are you sure?" }, method: :delete

/photos/create.js.erb

$('#photos').html("<%= j render(@photo) %>");

/javascripts/photos.js.coffee

jQuery ->
  $('#new_photo').fileupload
    dataType: 'script'
Dair
  • 77
  • 1
  • 7
  • in your form upload add remote: true, this will enable ajax request – mrvncaragay Jan 24 '16 at 10:04
  • @Marv-C, thanks for your reply! I added it to my form, still not working! Actually I was following this tutorial http://www.youtube.com/watch?v=x23aIQPa-DY, and it worked for one model with ajax rendering, but doesn't work in my case with two models, though I can upload images, just no ajax rendering.. – Dair Jan 24 '16 at 10:13
  • You don't need `remote: true` for jquery-file-upload; it's handled by the plugin – Richard Peck Jan 24 '16 at 10:23
  • @RichPeck you're right. im also trying to debug this problem with no luck at all. – mrvncaragay Jan 24 '16 at 10:27
  • @RichPeck, is it even possible to render ajax for this plugin with nested forms? Uploading works, rendering not... – Dair Jan 24 '16 at 10:34
  • Yes it's possible. But you don't need nested forms – Richard Peck Jan 24 '16 at 10:38
  • @RichPeck, thanks for your reply! Then how should I organize my form with file_field? I also updated my post to check my models. – Dair Jan 24 '16 at 10:47
  • Posted all relevant code – Richard Peck Jan 24 '16 at 10:48

3 Answers3

0

use

$('#photos').html(escape_javascript("<%= j render(@photo) %>"));

see http://api.rubyonrails.org/classes/ActionView/Helpers/JavaScriptHelper.html#method-i-escape_javascript

tillmo
  • 607
  • 5
  • 11
  • Says that an alert won't fire in his `.js.erb` so I doubt a syntax change would do much – Richard Peck Jan 24 '16 at 10:23
  • have you tried to debug with Firebug? With the `network` tab, you can see what is being sent to the browser. With the error console, you can detect errors on the browser side. – tillmo Jan 24 '16 at 10:35
0

Several issues.

#app/controllers/projects_controller.rb
class ProjectsController < ApplicationController
   respond_to :js, :html

   def new
      @project = Project.new
      @project.photos.build #-> this will replace Photo.new in fields_for
   end

   def create
      @project = Project.new project_params
      @project.save
      respond_with @project
   end

   private

   def project_params
      params.require(:project).permit(photos_attributes: [:img_file])
   end
end 

#app/views/projects/new.haml
= form_for @project do |f|
    = f.fields_for :photos do |ff|
       = ff.file_field :img_file, multiple: true, id: 'new_photo'

When using nested attributes, you should never be declaring the name attribute of your nested fields. Not only is it against convention, but it also leaves the door open to both hacking & bugs.

If you are using nested attributes, you need to be passing the @project object first, which means the form will either be passing to projects#update or projects#create... not photos#create that you have now.

I would also strongly recommend using the responders gem, it will clear up your code massively.

--

If you wanted to create a new Photo object on its own, you'll want to use the following:

#config/routes.rb
resources :projects do
   resources :photos #-> url.com/projects/:project_id/photos/new
end

#app/controllers/photos_controller.rb
class PhotosController < ApplicationController
   respond_to :js, :html

   def new
      @project = Project.find params[:project_id]
      @photo   = @project.photos.new
   end

   def create
      @project = Project.find params[:project_id]
      @photo   = @project.photos.new photo_params
      @photo.save
      respond_with @photo
   end

   private

   def photo_params
      params.require(:photo).permit(:img_file)
   end
end

#app/views/photos/new.haml
= form_for @photo do |f|
   = f.file_field :img_field

Your JS code is incorrect...

$('#photos').html("<%= j render(@photo) %>");

By default, Rails handles "collections" by calling _[collection_singular_name].html.erb - in your case _photo.html.erb. It loops through the collection to show this each time. To fix yours, just remove the loop from your partial:

#app/views/photos/_photo.html.erb
= image_tag photo.img_file.thumb
= link_to 'Remove', photo, data: { confirm: "Are you sure?" }, method: :delete

Solution

Decide whether you're creating a project or photo.

If you are creating a photo, you should use a separate photos controller (outlined above). If you're creating a new project, you should use nested attributes properly. We've used JQuery-File-Upload multiple times before (you can sign up for free its only a test app):

enter image description here

Your code structure looks okay, only the controller & JS which have issues.


Update

To add a new photo through a project's edit form, just use the following:

#app/controllers/projects_controller.rb
class ProjectsController < ApplicationController
   def edit
      @project = Project.find params[:id]
      @project.photos.build
   end

   def update
      @project = Project.find params[:id]
      @project.update project_params
   end

   private

   def project_params
      params.require(:project).permit(photos_attributes: [:img_file])
   end
end

#app/views/projects/edit.html.erb
<%= form_for @project do |f| %>
   <%= f.fields_for :photos do |p| %>
      <%= p.file_field :img_file %>
   <% end %>
   <%= f.submit %>
<% end %>
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • thanks a lot! But what if I want to create a **new photo** in project's page (/projects/edit). How should I call this **= form_for @photo** there and render them? – Dair Jan 24 '16 at 11:20
  • You'd need a nested form - I can update about this if required – Richard Peck Jan 24 '16 at 11:22
  • 1
    Could you please update this in order to add new photo from project's edit page? I'm a little confused, to be honest. – Dair Jan 24 '16 at 11:25
  • sure, let me do that. – Richard Peck Jan 24 '16 at 11:29
  • thank you a lot for helping me. But it still doesn't work. Now my files don't attach and when I submit on form, it says **Missing template projects/update** I updated my post with current situation, please, have a look, maybe I missed something. – Dair Jan 24 '16 at 12:04
0

For ajax file upload to work in jquery-file-upload gem

you have to add :html => { :multipart => true} to your form

<%= form_for Upload.new, :html => { :multipart => true} } do |f| %> ... <%end%>

Please see the jQuery-File-Upload example form for reference