I am having problems uploading multiple files using paper clip,
my models are as such
slider has_many imgarrays
imgarrays has_many imageobjects
imageobjects have_attachment(as for paperclip)
I have no problems receiving a single image and saving it using paperclip on my other models, but i am not sure of how to handle the array returned by imgarrays param during a multiple file upload.
Here is my rails server logs:
Started POST "/slider" for 127.0.0.1 at 2012-07-23 10:14:17 +0800
Processing by SliderController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7HcHtSlOsU/bnxb9emhAsSl/GFBraIE6NxwijHl3REM=", "slider"=>{"question"=>"", "answer"=>"", "score"=>"", "industry_name"=>"",
"imgarrays"=>[#<ActionDispatch::Http::UploadedFile:0x007fb471e99f30 #original_filename="Icon.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"slider[imgarrays][]\"; filename=\"Icon.png\"\r\nContent-Type: image/png\r\n", #tempfile=#<File:/var/folders/2s/n9wb5x4534nfs1cbrlph32v00000gp/T/RackMultipart20120723-53499-1lyi4yf>>, #<ActionDispatch::Http::UploadedFile:0x007fb471e99dc8 #original_filename="Icon#2x.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"slider[imgarrays][]\"; filename=\"Icon#2x.png\"\r\nContent-Type: image/png\r\n", #tempfile=#<File:/var/folders/2s/n9wb5x4534nfs1cbrlph32v00000gp/T/RackMultipart20120723-53499-10lala2>>, #<ActionDispatch::Http::UploadedFile:0x007fb471e99d50 #original_filename="greenButton.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"slider[imgarrays][]\"; filename=\"greenButton.png\"\r\nContent-Type: image/png\r\n", #tempfile=#<File:/var/folders/2s/n9wb5x4534nfs1cbrlph32v00000gp/T/RackMultipart20120723-53499-or2rdk>>]}, "commit"=>"Create!"}
Completed 500 Internal Server Error in 18ms
ActiveRecord::AssociationTypeMismatch (Imgarray(#70206507050500) expected, got ActionDispatch::Http::UploadedFile(#70206487229960)):
app/controllers/slider_controller.rb:12:in `new'
app/controllers/slider_controller.rb:12:in `create'
Rendered /Users/Kinnovate/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.4ms)
Rendered /Users/Kinnovate/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.4ms)
Rendered /Users/Kinnovate/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (6.5ms)
new.html.erb for slider
<div>
<%= form_for #slider ,:url=>"/slider" , :html => { :multipart => true } do |f| %>
<%= f.label :question , "question"%>
<%= f.text_field :question %> </br>
<%= f.label :answer , "answer array (comma seperated)"%>
<%= f.text_field :answer %> </br>
<%= f.label :score , "score"%>
<%= f.text_field :score %> </br>
<%= f.label :industry_name , "industry"%>
<%= f.text_field :industry_name %> </br>
<%= f.label :attachedimg , "image"%>
<%= f.file_field :imgarrays, :multiple =>:true %> </br>
<%= f.submit "Create", class: "btn btn-large btn-primary" %>
<% end %>
</div>
<%= link_to 'Cancel', slider_index_path %>
Here is my code that worked well to upload multiple file using paperclip:
We can achieve using nested attributes or using normal easy method.
The following code shows normal method:
User.rb
has_many :images, :dependent => :destroy
Image.rb
has_attached_file :avatar, :styles => { :medium => "300x300>" }
belongs_to :user
users/views/new.html.erb
<%= form_for #user, :html => { :multipart => true } do |f| %>
......
....
<%= file_field_tag :avatar, multiple: true %>
<% end %>
Users_controller:
.....
if #user.save
# params[:avatar] will be an array.
# you can check total number of photos selected using params[:avatar].count
params[:avatar].each do |picture|
#user.images.create(:avatar=> picture)
# Don't forget to mention :avatar(field name)
end
end
Thats it. images got uploaded, this may not be the good way but it works.
Related
So I was working on my app and trying to put on an uploader feature.
First I generated a course uploader and allowed jpeg, jpg, png and gif.
Next I've added the ff code mount on my course model:
mount_uploader :thumb_image, CoursesUploader
mount_uploader :main_image, CoursesUploader
Next, I place the file upload form code on my new.html.erb file:
<div class="field">
<%= f.file_field :main_image %>
</div>
<div class="field">
<%= f.file_field :thumb_image %>
</div>
And when I tried to submit my form with my images uploaded it did not even show the index page instead I refresh the page and then see if it got uploaded and the form was submitted successfully but it did not.
I also look at the strong params on my controller and these two items are there:
# Never trust parameters from the scary internet, only allow the white list through.
def course_params
params.require(:course).permit(:title, :price, :body, :main_image, :thumb_image)
end
Any idea what am I missing here?
Here's something I got from my terminal after submission:
Started POST "/courses" for 127.0.0.1 at 2019-01-16 20:52:20 +0800
Processing by CoursesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"wlKpv8czsuC6AZjCctxYk203wry4cb0dnOYI9IoAkzRZNV2vB4/vREU5L5u4G7vh5ZhCbHZlJ6nHPN95qO+cbA==", "course"=>{"title"=>"Goody", "price"=>"33", "main_image"=>#<ActionDispatch::Http::UploadedFile:0x007f81e52eed48 #tempfile=#<Tempfile:/var/folders/3_/8bmsd3j13bxfdl1jp7gzvvsm0000gn/T/RackMultipart20190116-2359-17w6pb.jpg>, #original_filename="61230.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"course[main_image]\"; filename=\"61230.jpg\"\r\nContent-Type: image/jpeg\r\n">, "thumb_image"=>#<ActionDispatch::Http::UploadedFile:0x007f81e52eecd0 #tempfile=#<Tempfile:/var/folders/3_/8bmsd3j13bxfdl1jp7gzvvsm0000gn/T/RackMultipart20190116-2359-2mcy4i.jpg>, #original_filename="61230.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"course[thumb_image]\"; filename=\"61230.jpg\"\r\nContent-Type: image/jpeg\r\n">, "body"=>""}, "commit"=>"Create Course"}
(0.5ms) BEGIN
↳ app/controllers/courses_controller.rb:27
Course Exists (1.5ms) SELECT 1 AS one FROM "courses" WHERE "courses"."id" IS NOT NULL AND "courses"."slug" = $1 LIMIT $2 [["slug", "goody"], ["LIMIT", 1]]
↳ app/controllers/courses_controller.rb:27
(0.6ms) ROLLBACK
↳ app/controllers/courses_controller.rb:27
Rendering courses/new.html.erb within layouts/application
Rendered courses/new.html.erb within layouts/application (12.6ms)
Rendered shared/_application_nav.html.erb (6.2ms)
Rendered shared/_application_footer.html.erb (1.3ms)
Completed 200 OK in 394ms (Views: 356.6ms | ActiveRecord: 2.6ms)
UPDATE: FULL MODEL CONTENT
class Course < ApplicationRecord
include DefaultsConcern
enum status: { draft: 0, published: 1 }
validates_presence_of :title, :price, :body, :main_image, :thumb_image
mount_uploader :thumb_image, CoursesUploader
mount_uploader :main_image, CoursesUploader
extend FriendlyId
friendly_id :title, use: :slugged
end
FULL FORM CONTENT:
<h1>New Form</h1>
<%= form_for(#course) do |f| %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :price %>
<%= f.number_field :price %>
</div>
<div class="field">
<%= f.file_field :main_image %>
</div>
<div class="field">
<%= f.file_field :thumb_image %>
</div>
<div class="field">
<%= f.label :body %>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Validation failed as params[:course][:body] is nil due to which creating course rolled back
validates_presence_of :title, :price, :body, :main_image, :thumb_image
=> So just fillup body field in form or remove validates_presence_of :body
I can see the Image is ActionDispatch already but are you sure you created your table column like this -Regardless of creating table or adding_column-
I'm focusing on
:string, array: true, default: []
Migration should look like:
add_column :courses, :main_image, :string, array: true, default: []
As creating the column as String won't let carrierwave add it's object as an array inside it, so it should be an array
Also you can set thumb and main images in one uploader if you are going to change the size only, otherwise you're fine to use :thumb_image and :main_image but make sure the migration is correct
If you can't change it, just drop and re-create it
I'm struggling with what I think is a very simple error, and yet I don't have the Rails sophistication to detect where that error is.
I have the following form:
<%= form_with(url: '/bills/viewer', method: :get) do |f| %>
<%= f.label :congress, 'Congress (i.e. 112)' %>
<%= f.number_field :congress, class: 'form-control' %>
<%= f.label :bill_type, 'Bill type' %>
<%= f.radio_button :bill_type, 'hr' %><%= ' House of Representatives' %>
<%= f.radio_button :bill_type, 's' %><%= ' Senate' %>
<%= f.radio_button :bill_type, 'hjres' %> <%= 'House Joint Resolution' %>
<%= f.radio_button :bill_type, 'sjres' %><%= ' Senate Joint Resolution' %>
<%= f.radio_button :bill_type, 'hconres' %><%= ' House Concurrent Resolution' %>
<%= f.radio_button :bill_type, 'sconres' %><%= ' Senate Concurrent Resolution' %>
<%= f.radio_button :bill_type, 'hres' %><%= ' House Resolution' %>
<%= f.radio_button :bill_type, 'sres' %><%= ' Senate Resolution' %>
<%= f.label :bill_number, 'Bill number' %>
<%= f.number_field :bill_number, class: 'form-control' %>
<%= f.submit "Submit", class: 'form-control' %>
<% end %>
In my config/routes.rb file, I have the following line:
get '/bills/viewer', to: 'bills#show'
The idea is that I want the form to transfer the submitted information to the "show" action in my bills_controller.rb file, which I give below...
def show
#bill = Bill.where("congress = ? AND bill_type = ? AND bill_number = ?", bill_params[:congress], bill_params[:bill_type], bill_params[:bill_number]).take
if #bill.nil?
create
end
#bill_xml = RestClient.get(bill_params[:bill_link])
render :xml => #bill_xml
puts "Called to show!"
...and then for the user to be redirected to corresponding show.html.erb file, which I give below...
<% provide(:title, "#{ #bill[:congress] } #{ #bill[:bill_type].upcase } #{ #bill[:bill_number] } | ") %>
<h1><%= "#{ #bill[:congress] } #{ #bill[:bill_type].upcase } #{ #bill[:bill_number] }" %></h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= puts #bill_xml %>
<%= render #bill_xml %>
</div>
</div>
<% puts "RENDERED..." %>
The two "puts" lines are in there for my own debugging purpose. The one in the show method behaves as expected, and my console displays "Called to show!". The other puts line, "RENDERED..." is not displayed. Moreover, the process completes to 200 OK.
I include my console's output upon clicking "Submit" below...
Started GET "/bills/viewer?utf8=%E2%9C%93&congress=112&bill_type=hr&bill_number=1027&commit=Submit" for 127.0.0.1 at 2018-07-05 15:05:51 -0700
Processing by BillsController#show as JS
Parameters: {"utf8"=>"✓", "congress"=>"112", "bill_type"=>"hr", "bill_number"=>"1027", "commit"=>"Submit"}
Unpermitted parameters: :utf8, :commit
Unpermitted parameters: :utf8, :commit
Unpermitted parameters: :utf8, :commit
Bill Load (0.1ms) SELECT "bills".* FROM "bills" WHERE (congress = '112' AND bill_type = 'hr' AND bill_number = '1027') LIMIT ? [["LIMIT", 1]]
Unpermitted parameters: :utf8, :commit
Called to show!
Completed 200 OK in 2980ms (Views: 0.6ms | ActiveRecord: 0.7ms)
But if the form were to be redirecting to show.html.erb the console output ought to return 3XX, no?
My (evidently wrong) understanding is that when I call the show action in my bills_controller, the website should automatically redirect to the views/bills/show.html.erb page. Why is this not the case, and how can I idiomatically correctly edit my code so that the desired redirect occurs?
Help is much appreciated.
The error was resolved by setting local: true within the form_with tag. Nevertheless, I am unclear as to why
This is from Rails Guides:
"By default form_with submits forms using Ajax thereby skipping full page redirects. To make this guide easier to get into we've disabled that with local: true for now."
I want an update method in the controller to get parameters in a specific format. The current format by which I am getting the parameters is
Parameters: {"utf8"=>"✓", "authenticity_token"=>"temp", "performance_areas"=>{"0"=>{"performance_area"=>"New item"}, "1"=>{"performance_area"=>"Delete Item"}, "commit"=>"Submit"}
This is being generated as a name in my text field with 0 and 1 indicating the areas index. I want some additional parameters in this in the following format:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"temp", "performance_areas"=>{"0"=>{id: 1, description: "This is a test","performance_area"=>"New item"}, "1"=>{id: 2, description: "This is a test2","performance_area"=>"Delete Item"}, "commit"=>"Submit"}
Any pointers how to get the parameters in the way I want. I do have performance_areas that has the id and description in it. Do let me know if any further clarification is required.
EDIT: Form code (just pasting the critical section of the long code)
<%= form_tag({:performance => :update}, :method => :put) do %>
<% #performance_areas.each_with_index do |performance_area, i| %>
<%= hidden_field_tag :performance_area, performance_area, :name => "performance_areas[#{i}][performance_area]" %>
<%= submit_tag %>
I think you want this, I am assuming that both id and description are in performance_area object
<%= form_tag({:performance => :update}, :method => :put) do %>
<% #performance_areas.each_with_index do |performance_area, i| %>
<%= hidden_field_tag :id, performance_area.id, :name => "performance_areas[#{i}][id]" %>
<%= hidden_field_tag :description, performance_area.description, :name => "performance_areas[#{i}][description]" %>
<%= hidden_field_tag :performance_area, performance_area, :name => "performance_areas[#{i}][performance_area]" %>
<%= submit_tag %>
<% end %>
I have a Listings model which accepts_nested_attributes_for an Asset model. On my site users are allowed to upload multiple photos per listing but each listing itself only has one asset:
class Listing < ActiveRecord::Base
has_one :asset, inverse_of: :listing
accepts_nested_attributes_for :asset, allow_destroy: true
end
and then the asset has the multiple attached files
class Asset < ActiveRecord::Base
belongs_to :listing, inverse_of: :asset
has_attached_file :photo1
has_attached_file :photo2
has_attached_file :photo3
validates :listing_id, presence: true
end
(like I said i'm using paperclip so i have all the necessary validations etc I just took them out to make this shorter and only show what's necessary)
In my ListingsController the new action is:
def new
#listing = Listing.new
#listing.build_asset
end
and this is the create action:
def create
#listing = Listing.new(listing_params)
#listing.user = User.find_by_username(params[:user_id])
respond_to do |format|
if #listing.save
format.html { redirect_to user_listing_path(#listing.user, #listing), notice: 'Listing was successfully created.' }
format.js {}
else
#listing.build_asset
format.html { render :new}
format.js {}
end
end
end
Now, when I create a listing, whether it comes from the new or 'create' action, the photos don't get saved and I get the error on my form Asset listing can't be blank. Now I know #listing.build_asset has to be working because the actual file upload fields show up, but for whatever reason it isn't connecting that asset with that listing.
My form view is pretty long so I'll abbreviate it:
<%= javascript_include_tag "listing/global_listing_form.js" %>
<div class="row">```
<%= form_for [current_user, #listing], :html => { :multipart => true } do |f| %>
<% if #listing.errors.any? %>
<div id="error_explanation">
Please correct the following <%= pluralize(#listing.errors.count, "error") %>:
<ul>
<% #listing.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div id="listing-form-product-info">
<%= render 'assets/upload_photos', f: f %>
<div class="actions">
<%= f.submit %>
<% end %>
</div>
</div> <!-- end listing-form-product-info -->
</div>
and the render 'assets/upload_photos', f: f renders this:
<div id="uploads_container">
<br>
<h3 class="button">The first photo will be your display photo</h3>
<br>
<%= f.fields_for :asset do |asset_photo| %>
<%= asset_photo.file_field :photo1, class: "upload-field" %>
<%= asset_photo.file_field :photo2, class: "upload-field" %>
<%= asset_photo.file_field :photo3, class: "upload-field" %>
<% end %>
</div>
So as I said, the problem is that the asset file fields show up, but when the form is actually submitted there is no relationship between that built asset and the listing it was created for.
Here's my listing_params method as requested:
def listing_params
params.require(:listing).permit(:user_id, :brand_id, :category_id, :size_id, :gender_id, :title, :description, :original_price, :price, :condition,:tag_list, asset_attributes: [:id, :photo1, :photo2, :photo3])
end
Here are the params from a listing I just tried creating:
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"3YjdJZWfClaUvTCW7MVdQ1hTBLPMow8QISBBQ1daI70=",
"listing"=>{
"gender_id"=>"1",
"category_id"=>"11",
"asset_attributes"=>{
"photo1"=>#<ActionDispatch::Http::UploadedFile:0x007f535cccdf10 #tempfile=#<Tempfile:/tmp/RackMultipart20140529-5-ska7i8>,
#original_filename="tumblr_mkk8iwuXCD1r05jkho1_1280.jpg",
#content_type="image/jpeg",
#headers="Content-Disposition: form-data;
name=\"listing[asset_attributes][photo1]\";
filename=\"tumblr_mkk8iwuXCD1r05jkho1_1280.jpg\"\r\nContent-Type: image/jpeg\r\n">,
"photo2"=>#<ActionDispatch::Http::UploadedFile:0x007f535cccddd0 #tempfile=#<Tempfile:/tmp/RackMultipart20140529-5-1ospj13>,
#original_filename="rsaah300_menthe.jpeg", #content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"listing[asset_attributes][photo2]\"; filename=\"rsaah300_menthe.jpeg\"\r\nContent-Type: image/jpeg\r\n">,
"photo3"=>#<ActionDispatch::Http::UploadedFile:0x007f535cccdc18 #tempfile=#<Tempfile:/tmp/RackMultipart20140529-5-edwbz1>, #original_filename="9200703.jpg", #content_type="image/jpeg",
#headers="Content-Disposition: form-data;
name=\"listing[asset_attributes][photo3]\";
filename=\"9200703.jpg\"\r\nContent-Type: image/jpeg\r\n">},
"title"=>"Mint Disco Pants",
"brand_id"=>"1",
"original_price"=>"80",
"price"=>"47",
"description"=>"American Apparel Mint High-waist disco pants\r\nBrand New, Never worn\r\n\r\nDescription from American Apparel site:\r\nForm-fitting, high-waist stretch pants made from a heavyweight Nylon/Elastane blend that creates a flattering slimming effect.\r\n\r\n• Nylon Spandex (90% Nylon / 10% Elastane) construction \r\n• Medium is approximately 30” (76.2cm) in total length \r\n• Metal zipper and button closure \r\n• Dual back pockets \r\n• Form-fitting \r\n• When in doubt on sizing, order down\r\n",
"size_id"=>"30",
"condition"=>"New without tags",
"tag_list"=>"high waisted, disco pants, disco"},
"commit"=>"Create Listing",
"user_id"=>"lexy"}
also, perhaps worth noting!
When I create a listing without uploading any photos, the listing is created. When I then go to edit the listing and add photos, the photos work and it recognizes that those photos belong to that listing. Which doesn't make sense since they are using the exact same form!
I ended up solving this by removing the listing_id validation on the asset model.
I have implemented nested attributes using railscasts and I am using devise in application. Here is the simple structure.
I have two model ie Group and Invite.
Group Model has
accepts_nested_attributes_for :invites, :reject_if => lambda { |a| a[:email].blank? }, :allow_destroy => true
and it works perfectly fine.
here is the hash of the parameters.
Parameters: {"utf8"=>"✓", "authenticity_token"=>"uI0HmJrIE9Qh3pZW2qIJymeON/yjbFSgcH8bRx/x5Oo=", "group"=>{"name"=>"Test Group", "description"=>"", "invites_attributes"=>{"0"=>{"name"=>"Test User", "email"=>"test#example.com", "_destroy"=>"false"}}}, "commit"=>"Create Group"}
Now the problem is I want to store invitee user_id in invites table, But I can access current_user in invite model. So how can I modify the hash in order to save current_user id in invite model.
Basically things will be easy if my hash parameters is:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"uI0HmJrIE9Qh3pZW2qIJymeON/yjbFSgcH8bRx/x5Oo=", "group"=>{"name"=>"Test Group", "description"=>"", "invites_attributes"=>{"0"=>{"name"=>"Test User", "email"=>"test#example.com", "_destroy"=>"false", :invited_by => "1" }}}, "commit"=>"Create Group"}
How can I modify hash at controller end? or is there is better way to achieve this.
Maybe you could try using hidden_field.
So, you may write something like this (based on the Railscasts):
# /app/views/surveys/_question_fields.html.erb
<div class="fields">
<p>
<%= f.hidden_field :user_id, :value => "1" %>
<%= f.label :content, "Question" %>
<%= link_to_remove_fields "remove", f %><br />
<%= f.text_area :content, :rows => 3 %><br />
</p>
<% f.fields_for :answers do |builder| %>
<%= render 'answer_fields', :f => builder %>
<% end %>
<p><%= link_to_add_fields "Add Answer", f, :answers %></p>
</div>
From APIdock:
One important thing to remember is that this is NOT hidden in the
source code and can be modified by an evil user so all input in a
hidden field should be considered as untrustworthy and checked just
like a visible field.
Ref:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-hidden_field
http://apidock.com/rails/ActionView/Helpers/FormHelper/hidden_field