newbie
newbie

Reputation: 600

Rails Paperclip Error: No handler found for

This is quite a common error and I have went through many answers but nothing worked for me. Can you please help, where I am going wrong?

Scenario: I have an item and image table and when user adds an item, he/she must add at least one image. When I save the form after attaching an image it gives an error. The code snippets and error screenshot are attached below:

item.rb

class Item < ApplicationRecord
  belongs_to :user, class_name: 'User', foreign_key: :user_id
  has_many :images, class_name: 'Image', foreign_key: :item_id, dependent: :destroy
  accepts_nested_attributes_for :images, allow_destroy: true
end

image.rb

class Image < ApplicationRecord
  belongs_to :item, foreign_key: :item_id, optional: true

  has_attached_file :image, styles: { small: '64x64', med: '100x100', large: '200x200' },
                    default_url: '/images/:id/:filename'
  validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end

items_controller.rb

class ItemsController < ApplicationController

  def new
    @item = Item.new
    @item.images.build
    #new.html.erb
  end

  def create
    @item = Item.new(item_params.merge(user_id: current_user.id))
    if @item.save
      redirect_to items_path
    else
      render :new
    end
  end

  private

  def item_params
    params.require(:item).permit(:name, :category, :qty, :cost, :description,
                                 :city, :postal_code, :country,
                                 images_attributes: [:id, :item_id, :_destroy, image: []])
  end
end

new.html.erb

<div class="container">
  <h2> <% if current_user.items.blank? %> Become a seller! <% end %> Add a new item </h2> <br>
  <%= form_for @item, url: {action: :create}, html: { multipart: true } do |f| %>
      <%= item_error_messages! %>
      <div class="form-group">
        <%= f.label :name, class:'control-label col-sm-2' %>
        <div class="col-sm-10">
          <%= f.text_field :name, class: 'form-control', placeholder: 'Enter name' %>
        </div>
      </div>

      <%= f.fields_for :images, @item.images.build do |img| %>
          <%= img.file_field :image, multiple: true %>
      <% end%>

      <br><br>
      <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10" style="margin-bottom: 40px;">
          <%= f.submit 'Save', class:'btn btn-default' %>
        </div>
      </div>
  <% end %>
</div>

Error:

enter image description here

What could be the possible issue? Most of the solutions I've read suggest adding multipart: true in form tag but it is already there.

Thanks

Upvotes: 0

Views: 2526

Answers (1)

Pedro Gabriel Lima
Pedro Gabriel Lima

Reputation: 1172

I think you problem is related with the fact that you are trying to save more than one attached file per model. Apparently, Paperclip don't treat this case very well, so you need to do it by your own hand.

If you want to save multiples files at the same time, you can follow the accept answer in the link below that example how to achieve that:

Just a resume from the link below:

1 - To save multiple files in the above example you, do not need add multiple: true option, it will cause an error when saving.

2 - About params: This will cause an error because the model does not know what to do with an array of images

3 - To save more than one file at the same time, you need to use your own handler

Rails 4 multiple file attachments with Paperclip

Good luck!

#UPDATE

Ideas about to how save multiples file at once:

1 - You will need to have a form with a dynamically input for files. So each input can get the entry for each file. You can achieve that writing your own .js lib or using a gem like "Cocoon". You will be using nested attributes here.

2 - The strong parameter in your controller will be accepting you Item model and an array of files.

3 - You will have to edit your method to save your data. E.g (in your case @item.save won't work because paperclips it's not design to accept an array of files). So, in your Item model you will have to write a method similar to the below:

(pseudo-code)

def save(item_attributes, array_of_files)
 @item = Item.new( -- add here only Item attributes --)
 @item.save

 # Here you are creating a model file for each file you are saving.
 # So there will be N file model for 1 item.
 for file in array_of_files
   @file = File.new( @item.id, file)
   @file.save
 end

 # here you can implement transaction in case a error occurs. 
 # and shows the error to your client through Item model 
 # google how to do this (transaction and Active Record class).
end

Upvotes: 1

Related Questions