Reputation: 77
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'
Upvotes: 1
Views: 811
Reputation: 76784
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
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):
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 %>
Upvotes: 0
Reputation: 6243
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
Upvotes: 0
Reputation: 616
use
$('#photos').html(escape_javascript("<%= j render(@photo) %>"));
Upvotes: 0