Paperclip + ImageMagick help needed

Hey there, I want to be able to upload multiple images at once on my website. I can only upload one image at a time at the moment. Can anybody lead me in the right direction? Here's my code

/app/models/listing.rb

class Listing < ActiveRecord::Base has_attached_file :image, :styles => { :medium => "200x", :thumb => "100x100>" }, :default_url => "default.jpg" validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/ end

/app/controllers/listings_controller.rb

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

# Never trust parameters from the scary internet, only allow the white list through. def listing_params params.require(:listing).permit(:name, :description, :price, :image) end end

/app/views/listings/_form.html.erb

<%= form_for @listing, :html => { :multipart => true } do |f| %> ... ... <div class="form-group"> <%= f.file_field :image, class: "form-control" %> </div> <div class="form-group"> <%= f.submit class: "btn btn-primary" %> </div> <% end %>

/app/views/listings/show.html.erb

<p id="notice"><%= notice %></p>

<%= image_tag @listing.image.url(:medium) %> ...

/app/views/listings/index.html.erb

<h1>Listing listings</h1>

<table> <thead> <tr> <th>Image</th> <th>Name</th> ... <tbody> <% @listings.each do |listing| %> <tr> <td><%= image_tag listing.image.url(:medium) %></td> <td><%= listing.name %></td> ...

Hey there, I want to be able to upload multiple images at once on my website. I can only upload one image at a time at the moment. Can anybody lead me in the right direction? Here's my code

/app/models/listing.rb

class Listing < ActiveRecord::Base has_attached_file :image, :styles => { :medium => "200x", :thumb => "100x100>" }, :default_url => "default.jpg" validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/ end

/app/controllers/listings_controller.rb

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

# Never trust parameters from the scary internet, only allow the white list through. def listing_params params.require(:listing).permit(:name, :description, :price, :image) end end

/app/views/listings/_form.html.erb

<%= form_for @listing, :html => { :multipart => true } do |f| %> ... ... <div class="form-group"> <%= f.file_field :image, class: "form-control" %> </div> <div class="form-group"> <%= f.submit class: "btn btn-primary" %> </div> <% end %>

/app/views/listings/show.html.erb

<p id="notice"><%= notice %></p>

<%= image_tag @listing.image.url(:medium) %> ...

/app/views/listings/index.html.erb

<h1>Listing listings</h1>

<table> <thead> <tr> <th>Image</th> <th>Name</th> ... <tbody> <% @listings.each do |listing| %> <tr> <td><%= image_tag listing.image.url(:medium) %></td> <td><%= listing.name %></td> ...

In order to do this (no matter which file attachment system you choose) you will need to refactor your application slightly. You need a model instance *per* image uploaded, so the usual way to do this is with a nested form. You create a form on a parent object that `has_many` of the image objects. If the Listing model is the parent, then you can add an Image model to belong to that listing, in a one-to-many relationship. Then you set up the following (this is pseudocode, off the top of my head, not guaranteed to work as written, but the right idea, IMO):

class Listing < ActiveRecord::Base   has_many :images   accepts_nested_attributes_for :images, allow_destroy: true, reject_if: :all_blank end

class Image < ActiveRecord::Base   belongs_to :listing   has_attached_file :image end

class ListingsController < ApplicationController ... all the usual CRUD actions here   private   def listing_params     params.require(:listing).permit(:name, :description, :price, images_attributes: [:id, :image, :_destroy])   end end

And finally, in your form_for @listing, you need to create a very particularly named field in order to get this all to work together:

<%= file_field_tag('listing_images_attributes_image', multiple: true, :name => "listing[images_attributes][image]") %>

That last part is ripped out of working code using Paperclip.

Things to note here: 1. It's using the file_field_tag generator (long-hand) rather than the f.file_field that you may be used to. This is so that the name can be exactly what it needs to be to "trick" the accepts_nested_attributes_for helper into accepting the attached files. 2. The multiple: true thing means that you will need a modern browser to use this (HTML5 feature). 3. The empty square-brackets in the middle of the name are the "secret sauce" that cause the individual files in the multiple file form element to be sent as separate files, rather than the last one "winning" or the data being concatenated and sent as form post body instead. 4. This type of field is only useful on an initial create or upload screen, not if you want to edit each of the attached files individually. I would put this particular form on the #new screen.

Once you have this working, you will need to make your #edit screen a more traditional nested form. Read this for an example and further ideas: #196 Nested Model Form (revised) - RailsCasts

Walter

Hey Walter. Thanks for all of the help!

I went through all of your steps. What should I write on my view page?

<div class="row">   <div class="col-md-6">     <div class="thumbnail">       <%= image_tag @listing.image.url %>     </div>   </div>   <div class="col-md-6">     <h3><%= @listing.name %></h3>     <p><%= number_to_currency(@listing.price) %></p>     <p><%= @listing.description %></p>     <br>     <div class="center">       <%= link_to "Buy It Now", new_listing_order_path(@listing), class: "btn btn-primary", data: { no_turbolink: true } %>     </div>   </div> </div>

<% if current_user == @listing.user %>   <%= link_to 'Edit', edit_listing_path(@listing), class: "btn btn-link" %> | <% end %> <%= link_to 'Back', listings_path, class: "btn btn-link" %>

Attachments: http://www.ruby-forum.com/attachment/11261/Screen_Shot_2016-02-10_at_7.32.27_PM.png

Hey Walter. Thanks for all of the help!

I went through all of your steps. What should I write on my view page?

If you want to show all the images for a listing, the simplest thing is:

<%- @listing.images.each do |image| %> <%= image_tag image.image_url %> <%- end %>

Now there are lots of other refinements you could add to this -- sizing the images, extra HTML around each one, setting their order, etc. -- but this will get you started.

Walter

What a great post, thanks Walter. That is going straight into useful-notes-to-keep-in-case-I-ever-want-to-do-it.

Colin