I'm aware that there are several posts on Stackoverflow and several tutorials about this subject. None of them however manage to solve my issue and most of them are outdated as well.
I am trying to add multiple images to a project using the paperclip gem in Rails 4. When i try uploading it i do see the asset attached in the params.
They do not seem to be added to the project_paramns though..
Hope someone can help me out here.
This is my projects_controller
class ProjectsController < ApplicationController
  before_filter :find_project, only: [:show, :edit, :update, :destroy]
  def index
   @projects = Project.all
  end
  def show
  end
  def new
    @project = Project.new
  end
  def create
    @project = Project.new(project_params)
    @project.save
    redirect_to project_path(@project)
  end
  def edit
  end
  def update
    @project.update(project_params)
    redirect_to project_path(@project)
  end
  def destroy
    @project.destroy
    redirect_to projects_path
  end
  protected
    def project_params
      params.require(:project).permit(:name, :description, :asset)
    end
    def find_project
      @project = Project.find(params[:id])
    end
end
My project model
class Project < ActiveRecord::Base
  has_many :assets, :dependent => :destroy
  validates_associated :assets
  validates_presence_of :name, :on => :create, :update => "can't be blank"
  validates_presence_of :description, :on => :create, :update => "can't be blank"
  accepts_nested_attributes_for :assets
end
My asset model
class Asset < ActiveRecord::Base
    belongs_to :project
  # Paperclip
  has_attached_file :image,
    :styles => {
      :thumb=> "100x100#",
      :small  => "150x150>",
      :medium => "300x300>",
      :large =>   "400x400>" }
  validates_attachment :image, content_type: { content_type: ["image/jpg", "image/jpeg",     "image/png", "image/gif"] }
end
And my form partial (Sorry it's in HAML)
= simple_form_for @project do |f|
  %ul
    - @project.errors.full_messages.each do |error|
      %li= error
  .row
    .small-1.columns    
      = f.label :name, :class => "left inline"
    .small-11.columns
      = f.input_field :name
  .row
    .small-1.columns
      = f.label :description, :class => "left inline"
    .small-11.columns 
      = f.input_field :description, as: :text
  .row
    = f.simple_fields_for :asset do |a|
      .small-1.columns
        = a.label :image, :class => "left inline"
      .small-11.columns
        = file_field_tag :image, multiple: true,
  .row
    .small-9.small-offset-1.columns
      = f.submit nil ,:class => "button [radius round]"
Request Parameters
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"4iK1kUNvKvoJVOKoivz/pcLAe6LY0cUJikQioxa8BIs=", "project"=>{"name"=>"adf", "description"=>"adf", "asset"=>{"image"=>[#<ActionDispatch::Http::UploadedFile:0x007fb808357d80 @tempfile=#<Tempfile:/var/folders/v_/98sxm8bn24qbqj_jmj40fv400000gn/T/RackMultipart20140607-34739-dvlzt7>, @original_filename="enabling-gzip-compression.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"project[asset][image][]\"; filename=\"enabling-gzip-compression.jpg\"\r\nContent-Type: image/jpeg\r\n">, #<ActionDispatch::Http::UploadedFile:0x007fb808357d58 @tempfile=#<Tempfile:/var/folders/v_/98sxm8bn24qbqj_jmj40fv400000gn/T/RackMultipart20140607-34739-lwkioi>, @original_filename="minimize_http_requests.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"project[asset][image][]\"; filename=\"minimize_http_requests.png\"\r\nContent-Type: image/png\r\n">]}}, "commit"=>"Update Project", "action"=>"update", "controller"=>"projects", "id"=>"11"}
Now i've also got an error showing up in my terminal:
Unpermitted parameters: asset
Edit:
A combination of @pavan's and @kiri thorat's answers have helped me get something showing up in project_params, the output it gives now is:
{"name"=>"Test", "description"=>"Test", "assets_attributes"=>{"0"=>{}}}
Any clue on what's going on here?
After @kirithorat's latest update things seem to be good on the parameter side of things.
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"4iK1kUNvKvoJVOKoivz/pcLAe6LY0cUJikQioxa8BIs=", "project"=>{"name"=>"Test", "description"=>"Test", "assets_attributes"=>{"0"=>{"image"=>#<ActionDispatch::Http::UploadedFile:0x007fcd383c9a08 @tempfile=#<Tempfile:/var/folders/v_/98sxm8bn24qbqj_jmj40fv400000gn/T/RackMultipart20140610-36517-7ek1oq>, @original_filename="enabling-gzip-compression.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"project[assets_attributes][0][image]\"; filename=\"enabling-gzip-compression.jpg\"\r\nContent-Type: image/jpeg\r\n">}}}, "commit"=>"Update Project", "action"=>"update", "controller"=>"projects", "id"=>"13"}
The assets are still not being saved though.
Update after implementing @Valikiliy's suggestions
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"4iK1kUNvKvoJVOKoivz/pcLAe6LY0cUJikQioxa8BIs=", "project"=>{"name"=>"Test", "description"=>"Test", "image"=>#<ActionDispatch::Http::UploadedFile:0x007fcd3a08d0b8 @tempfile=#<Tempfile:/var/folders/v_/98sxm8bn24qbqj_jmj40fv400000gn/T/RackMultipart20140610-36517-rgy95n>, @original_filename="minimize_http_requests.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"project[image]\"; filename=\"minimize_http_requests.png\"\r\nContent-Type: image/png\r\n">}, "commit"=>"Update Project", "action"=>"update", "controller"=>"projects", "id"=>"16"}
Update: Added new form code on request
= simple_form_for(@project, :html => { :multipart => true }) do |f|
  %ul
    - @project.errors.full_messages.each do |error|
      %li= error
  .row
    .small-1.columns    
      = f.label :name, :class => "left inline"
    .small-11.columns
      = f.text_field :name
  .row
    .small-1.columns
      = f.label :description, :class => "left inline"
    .small-11.columns 
      = f.text_area :description
  .row
    = f.simple_fields_for :assets do |a|
      .small-1.columns
        = a.label :image, :class => "left inline"
      .small-11.columns
        - if a.object.new_record?
          = a.input :image, as: :file
        - else
          = image_tag a.object.image.url(:thumb)
          = a.input_field '_destroy', as: :boolean
  .row
    .small-9.small-offset-1.columns
      = f.submit nil ,:class => "button [radius round]"
Update
def project_params
  params.require(:project).permit(:name, :description, images: [], assets_attributes: [:_destroy, :id, :image])
end
def find_project
  @project = Project.find(params[:id])
  @project.assets.build if %w[new edit].include?(action_name) 
end
Update: Added model code
class Project < ActiveRecord::Base
  has_many :assets, :dependent => :destroy
  validates_presence_of :name, :on => :create, :update => "can't be blank"
  validates_presence_of :description, :on => :create, :update => "can't be blank"
  accepts_nested_attributes_for :assets, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
                To save multiple files in the above example you, do not need add multiple: true option, it will cause an error when saving, one file - one record assets table.
For resolve this, you can add multiple file fields, like this: add into controller:
def new
  @project = Project.new
  3.times{ @project.assets.build } 
end
def edit
  3.times{ @project.assets.build } 
end
for while list
.permit(..., assets_attributes: [ :_destroy, :id, :image ])
and in view like this:
= f.simple_fields_for :assets do |a|
  .small-1.columns
    = a.label :image, :class => "left inline"
    - if a.object.new_record?
      .small-11.columns
        = a.file_field :image
    - else
      .small-11.columns
        = image_tag a.object.image.url(:thumb)
        = a.input_field '_destroy', as: :boolean
If you try to send multiple images like this:
# view
a.file_field :image, multiple: true
# controller
.permit(..., assets_attributes: [ :_destroy, :id, image: [] ])
This will cause an error because the Asset model does not know what to do with an array of images.
To save more than one file at the same time, you need to use your own handler, for example:
model: add the images= method
def images=(files = [])
  assets.create(image: f)
end
controller: move images: [] outside of the assets_attributes
.permit(..., images: [], assets_attributes: [ :_destroy, :id ])
view: remove the fields_for and nested attributes
  .row
    .small-1.columns
      =f.file_field :images, multiple: true
  .row
    = f.simple_fields_for :assets do |a|
      .small-1.columns
        = a.label :image, :class => "left inline"
....
                        You have 1-M relationship between Project and Asset models i.e., 
Project has_many assets
so, in your form partial simple_fields_for should look like
= f.simple_fields_for :assets do |a| 
Notice assets in plural and NOT asset in singular
In your current code, you used simple_fields_for with singular asset which is why your params is generated incorrectly and you receive asset key in params hash instead of receiving assets_attributes key which results in the warning as Unpermitted parameters: asset.
Once you correct the form partial you would receive the correct keys in params hash upon form submission. Now, as @Pavan pointed out next problem that I see is you have not permitted the assets_attributes correctly in the controller.
You need to update the project_params method as below:
def project_params
  params.require(:project).permit(:name, :description, assets_attributes: [:image])
end
Notice assets_attributes with assets in plural
UPDATE
You would need to add @project.assets.build in new and edit action of ProjectsController in order to see the fields for assets in the new and edit view.
Also, I would suggest adding :id in the list of permitted attributes for assets_attributes in project_params as below:
  params.require(:project).permit(:name, :description, assets_attributes: [:id, :image])
Few more problems that I see is in the form partial are 
As you are uploading a file, you should specify :html => {:multipart => true} in the form.
Change
= simple_form_for @project do |f|
To
= simple_form_for @project, :html => {:multipart => true} do |f|
Project has_many assets and every asset record would have only one image, so remove multiple: true. Also, as you are using simple_form, its advisable to use simple_form helper method for uploading file.
Change
= file_field_tag :image, multiple: true,
To
= a.input :image, as: :file
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