问题
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
回答1:
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"
....
回答2:
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 oneimage
, so removemultiple: true
. Also, as you are usingsimple_form
, its advisable to usesimple_form
helper method for uploading file.Change
= file_field_tag :image, multiple: true,
To
= a.input :image, as: :file
回答3:
Your project_params
should be like this
def project_params
params.require(:project).permit(:name, :description, assets_attributes: [:image])
end
And also,why you are using protected
? i guess you should be using private
.
来源:https://stackoverflow.com/questions/24099045/rails-4-multiple-file-attachments-with-paperclip