How can I upload multiple images from a file selection window using Rails 4 and CarrierWave? I have a post_controller
and post_attachments
model. How can I do this?
Can someone provide an example? Is there a simple approach to this?
A file can be uploaded to server in two ways, one we can send the image as base64 string as plain text and another one is using multipart/form-data . The first one is the worst idea as it sends the entire image as plain text.
This is solution to upload multiple images using carrierwave in rails 4 from scratch
Or you can find working demo : Multiple Attachment Rails 4
To do just follow these steps.
rails new multiple_image_upload_carrierwave
In gem file
gem 'carrierwave' bundle install rails generate uploader Avatar
Create post scaffold
rails generate scaffold post title:string
Create post_attachment scaffold
rails generate scaffold post_attachment post_id:integer avatar:string rake db:migrate
In post.rb
class Post < ActiveRecord::Base has_many :post_attachments accepts_nested_attributes_for :post_attachments end
In post_attachment.rb
class PostAttachment < ActiveRecord::Base mount_uploader :avatar, AvatarUploader belongs_to :post end
In post_controller.rb
def show @post_attachments = @post.post_attachments.all end def new @post = Post.new @post_attachment = @post.post_attachments.build end def create @post = Post.new(post_params) respond_to do |format| if @post.save params[:post_attachments]['avatar'].each do |a| @post_attachment = @post.post_attachments.create!(:avatar => a) end format.html { redirect_to @post, notice: 'Post was successfully created.' } else format.html { render action: 'new' } end end end private def post_params params.require(:post).permit(:title, post_attachments_attributes: [:id, :post_id, :avatar]) end
In views/posts/_form.html.erb
<%= form_for(@post, :html => { :multipart => true }) do |f| %> <div class="field"> <%= f.label :title %><br> <%= f.text_field :title %> </div> <%= f.fields_for :post_attachments do |p| %> <div class="field"> <%= p.label :avatar %><br> <%= p.file_field :avatar, :multiple => true, name: "post_attachments[avatar][]" %> </div> <% end %> <div class="actions"> <%= f.submit %> </div> <% end %>
To edit an attachment and list of attachment for any post. In views/posts/show.html.erb
<p id="notice"><%= notice %></p> <p> <strong>Title:</strong> <%= @post.title %> </p> <% @post_attachments.each do |p| %> <%= image_tag p.avatar_url %> <%= link_to "Edit Attachment", edit_post_attachment_path(p) %> <% end %> <%= link_to 'Edit', edit_post_path(@post) %> | <%= link_to 'Back', posts_path %>
Update form to edit an attachment views/post_attachments/_form.html.erb
<%= image_tag @post_attachment.avatar %> <%= form_for(@post_attachment) do |f| %> <div class="field"> <%= f.label :avatar %><br> <%= f.file_field :avatar %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>
Modify update method in post_attachment_controller.rb
def update respond_to do |format| if @post_attachment.update(post_attachment_params) format.html { redirect_to @post_attachment.post, notice: 'Post attachment was successfully updated.' } end end end
In rails 3 no need to define strong parameters and as you can define attribute_accessible in both the model and accept_nested_attribute to post model because attribute accessible is deprecated in rails 4.
For edit an attachment we cant modify all the attachments at a time. so we will replace attachment one by one, or you can modify as per your rule, Here I just show you how to update any attachment.
If we take a look at CarrierWave's documentation, this is actually very easy now.
https://github.com/carrierwaveuploader/carrierwave/blob/master/README.md#multiple-file-uploads
I will use Product as the model I want to add the pictures, as an example.
Get the master branch Carrierwave and add it to your Gemfile:
gem 'carrierwave', github:'carrierwaveuploader/carrierwave'
Create a column in the intended model to host an array of images:
rails generate migration AddPicturesToProducts pictures:json
Run the migration
bundle exec rake db:migrate
Add pictures to model Product
app/models/product.rb class Product < ActiveRecord::Base validates :name, presence: true mount_uploaders :pictures, PictureUploader end
Add pictures to strong params in ProductsController
app/controllers/products_controller.rb def product_params params.require(:product).permit(:name, pictures: []) end
Allow your form to accept multiple pictures
app/views/products/new.html.erb # notice 'html: { multipart: true }' <%= form_for @product, html: { multipart: true } do |f| %> <%= f.label :name %> <%= f.text_field :name %> # notice 'multiple: true' <%= f.label :pictures %> <%= f.file_field :pictures, multiple: true, accept: "image/jpeg, image/jpg, image/gif, image/png" %> <%= f.submit "Submit" %> <% end %>
In your views, you can reference the images parsing the pictures array:
@product.pictures[1].url
If you choose several images from a folder, the order will be the exact order you are taking them from top to bottom.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With