Hello. I''ve been trying this out for the past two days and I can''t seem to get it. I''m going to have a page where you can upload x amount of images at once. Lets say 10 images need to be uploaded, all with a caption. I''d like to have a browse button to choose the file, then the caption. Now, if I put 10 of them in one form, fill them all out and submit, I get one form. It seems that all of the fields wind up overwriting eachother and I get the last one submitted. What I''m asking is if it is possible to say take THIS, THIS, and THAT, and make one row. Then take THIS(2), THIS(2), and THAT(2), and make yet another row. Thanks a lot, -- -Matt -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060308/50729c09/attachment.html
Mark Reginald James
2006-Mar-08 22:34 UTC
[Rails] Re: Creating multiple rows with one form
Matt Ramos wrote:> Hello. I''ve been trying this out for the past two days and I can''t seem > to get it. I''m going to have a page where you can upload x amount of > images at once. Lets say 10 images need to be uploaded, all with a caption. > > I''d like to have a browse button to choose the file, then the caption. > Now, if I put 10 of them in one form, fill them all out and submit, I > get one form. It seems that all of the fields wind up overwriting > eachother and I get the last one submitted. > > What I''m asking is if it is possible to say take THIS, THIS, and THAT, > and make one row. Then take THIS(2), THIS(2), and THAT(2), and make yet > another row.Assuming you have a model called "Image", having attributes "filename" and "caption", and you have a User model that has_many images. In the view: <%= form_tag %> <table> <% 10.times do |i| @image = @images[i] %> <tr> <%= file_columm_field ''image'', ''filename'', :index => i %> <%= text_field ''image'', ''caption'', :index => i %> </tr> <% end %> </table> <%= end_form_tag %> In the controller: def specify_images case request.method when :get then @images = Array.new(10) { Image.new } when :post all_valid = true @images = [] params[:image].each_value do |p| image = @user.images.build(p) @images << image all_valid &&= image.valid? end if !@images.empty? && all_valid @images.each { |image| image.save(false) } redirect_to :action => ''show_user'' else flash.now[:error] = ''No images entered'' if @images.empty? (10-@images.length).times { @images << Image.new } end end Different code would be needed to modify an existing set of images associated with a user, rather than just creating a new set. -- We develop, watch us RoR, in numbers too big to ignore.
Mark, Where is the :index parameter documented? Can it work with an id instead of index? Thanks, Chris Mark Reginald James wrote:> Matt Ramos wrote: >> and make one row. Then take THIS(2), THIS(2), and THAT(2), and make yet >> another row. > > Assuming you have a model called "Image", having attributes > "filename" and "caption", and you have a User model that > has_many images. > > In the view: > > <%= form_tag %> > <table> > <% 10.times do |i| > @image = @images[i] %> > <tr> > <%= file_columm_field ''image'', ''filename'', :index => i %> > <%= text_field ''image'', ''caption'', :index => i %> > </tr> > <% end %> > </table> > <%= end_form_tag %> > > > In the controller: > > def specify_images > case request.method > when :get then @images = Array.new(10) { Image.new } > when :post > all_valid = true > @images = [] > params[:image].each_value do |p| > image = @user.images.build(p) > @images << image > all_valid &&= image.valid? > end > if !@images.empty? && all_valid > @images.each { |image| image.save(false) } > redirect_to :action => ''show_user'' > else > flash.now[:error] = ''No images entered'' if @images.empty? > (10-@images.length).times { @images << Image.new } > end > end > > Different code would be needed to modify an existing set of > images associated with a user, rather than just creating a > new set. > > -- > We develop, watch us RoR, in numbers too big to ignore.-- Posted via http://www.ruby-forum.com/.
Mark Reginald James
2006-Mar-09 01:01 UTC
[Rails] Re: Creating multiple rows with one form
Chris Bruce wrote:> Where is the :index parameter documented? Can it work with an id > instead of index?The :index option is docmented here: http://api.rubyonrails.com/classes/ActionView/Helpers/FormHelper.html To index with ids, use the "object[]" notation, documented at the same place. -- We develop, watch us RoR, in numbers too big to ignore.
hi! i had similar problem and used: <%#= file_field_tag "images[#{i}][name]" %> but now i''ve changed it to use index. Thanks for the tip. BTW. i''ve created simple javascript so you can enter any number of file fields you like: in ''new'' action of parent controller (or probably you could in _form.rhtml) specify default number of file fields: @file_fields_no = 4 then in _form.rhtml <%= javascript_tag "var image_field_number=#{@file_fields_no}" %> <% @file_fields_no.times do |i| %> <%= file_field "images", "name", "index" => i %><br /> <% end %> <%=link_to_function ''add image'', ''add_image_upload_field(image_field_number); image_field_number++;'', :id => "add_image" %> javascript: function add_image_upload_field(id) { var image_field = ''<input type="file" id="images_'' + id + ''_name" name="images['' + id + ''][name]" size="30" /><br />''; new Insertion.Before("add_image", image_field); } -- Posted via http://www.ruby-forum.com/.
Thanks a lot. I''ll take a look at that when I get home from work and play around with it. Thanks :) On 3/9/06, szymek <g0nzo@o2.pl> wrote:> > hi! > > i had similar problem and used: > <%#= file_field_tag "images[#{i}][name]" %> > > but now i''ve changed it to use index. Thanks for the tip. > > BTW. i''ve created simple javascript so you can enter any number of file > fields you like: > > in ''new'' action of parent controller (or probably you could in > _form.rhtml) specify default number of file fields: > @file_fields_no = 4 > > then in _form.rhtml > <%= javascript_tag "var image_field_number=#{@file_fields_no}" %> > <% @file_fields_no.times do |i| %> > <%= file_field "images", "name", "index" => i %><br /> > <% end %> > <%=link_to_function ''add image'', > ''add_image_upload_field(image_field_number); image_field_number++;'', :id > => "add_image" %> > > javascript: > function add_image_upload_field(id) { > var image_field = ''<input type="file" id="images_'' + id + ''_name" > name="images['' + id + ''][name]" size="30" /><br />''; > new Insertion.Before("add_image", image_field); > } > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- -Matt -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060309/8ba8461f/attachment.html
Also, szymek, thanks for that. I planned on adding that later on. On 3/9/06, Matt Ramos <matt.ramos@gmail.com> wrote:> > Thanks a lot. I''ll take a look at that when I get home from work and play > around with it. > > Thanks :) > > > On 3/9/06, szymek < g0nzo@o2.pl> wrote: > > > > hi! > > > > i had similar problem and used: > > <%#= file_field_tag "images[#{i}][name]" %> > > > > but now i''ve changed it to use index. Thanks for the tip. > > > > BTW. i''ve created simple javascript so you can enter any number of file > > fields you like: > > > > in ''new'' action of parent controller (or probably you could in > > _form.rhtml) specify default number of file fields: > > @file_fields_no = 4 > > > > then in _form.rhtml > > <%= javascript_tag "var image_field_number=#{@file_fields_no}" %> > > <% @file_fields_no.times do |i| %> > > <%= file_field "images", "name", "index" => i %><br /> > > <% end %> > > <%=link_to_function ''add image'', > > ''add_image_upload_field(image_field_number); image_field_number++;'', :id > > > > => "add_image" %> > > > > javascript: > > function add_image_upload_field(id) { > > var image_field = ''<input type="file" id="images_'' + id + ''_name" > > name="images['' + id + ''][name]" size="30" /><br />''; > > new Insertion.Before("add_image", image_field); > > } > > > > -- > > Posted via http://www.ruby-forum.com/. > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > > -- > -Matt >-- -Matt -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060309/1bb1690e/attachment.html
Mark Reginald James
2006-Mar-10 04:56 UTC
[Rails] Re: Creating multiple rows with one form
szymek wrote:> i had similar problem and used: > <%#= file_field_tag "images[#{i}][name]" %> > > but now i''ve changed it to use index. Thanks for the tip. > ... > <% @file_fields_no.times do |i| %> > <%= file_field "images", "name", "index" => i %><br /> > <% end %>Note that if you use the index option this way you can''t persist the image objects for form redisplay after validation failure, including error field highlighting. To allow this you have to instead call the form helpers with each object of the array in turn: <% @file_fields_no.times do |i| @image = @images[i] %> <%= file_field "image", "name", "index" => i %><br /> <% end %> -- We develop, watch us RoR, in numbers too big to ignore.
I didn''t notice it, because i didn''t have any validation yet... I must admit i don''t really understand why this line is necessary: <% @image = @images[i] %> I have @property object that has many images, however i can''t just save @property.images, because from the form i get uploaded files and i want to store in the database just their names (i''m saving files on the disk also, but after modifying their sizes and names). So i pass @property and @images to the _form.rhml and later when i save @property object i have: def create @property = Property.new(params[:property]) if @property.save if !params[:images].empty? params[:images].length.times do |i| ... @property.images << Image.new(:name => image_filename) #save image and its thumbnail to the disk end end redirect_to :action => ''list'' else render :action => ''new'' end end But i don''t really now how to do it, so it will work with validation. And there''s also updating... I didn''t find anywhere a sample code how to do this, so i tried to do it myself, and i thought it works... unfortunately it does not. So how to do it properly? -- Posted via http://www.ruby-forum.com/.
It''s me again. I tried understand the code posted in the second post, but i can''t figure out how it works. What do these lines do: image = @user.images.build(p) #what does build method do? @images.each { |image| image.save(false) } #why''s ''false'' parameter here? -- Posted via http://www.ruby-forum.com/.
Mark Reginald James
2006-Mar-10 13:18 UTC
[Rails] Re: Creating multiple rows with one form
szymek wrote:> I must admit i don''t really understand why this line is necessary: > <% @image = @images[i] %>AR form helpers only work with a single Active Record model instance, stored in a controller instance variable. With the code you posted all helpers will display the @images object. The index option only gives them different names so that they become separate parameters when POSTed, it is not also an index into an array of AR objects.> I have @property object that has many images, however i can''t just save > @property.images, because from the form i get uploaded files and i want > to store in the database just their names (i''m saving files on the disk > also, but after modifying their sizes and names).Have you had a look at the file_column plugin, which does much of this automatically? -- We develop, watch us RoR, in numbers too big to ignore.
Mark Reginald James
2006-Mar-10 13:31 UTC
[Rails] Re: Creating multiple rows with one form
szymek wrote:> I tried understand the code posted in the second post, but i can''t > figure out how it works. What do these lines do: > > image = @user.images.build(p) #what does build method do?Equivalent to: image = Image.new( p.update(:user => @user) )> @images.each { |image| image.save(false) } #why''s ''false'' parameterSpeeds up the code by bypassing validation, since the validation has already been done. By the way, part of the last main line of this code got recognized as an email address, and got munged. With a few extra spaces, hopefully this should come through OK: (10 - @images.length).times { @images << Image.new } -- We develop, watch us RoR, in numbers too big to ignore.
Thanks for explaining. Does file_column pluing allow uploading many files in one form? Does it work with has_many/belongs_to relationship? If it does both these things, then i''ll switch immediately! :) But also it would be nice to know how to do it myself. Ok, here''s what i got now (it''s probalby 100th version :) ) in _form.rhtml: <% @file_fields_no.times do |i| %> <% @image = @images[i] %> <%= file_field "image", "name", "index" => i %><br /> <% end %> in property controller: def new @property = Property.new @file_fields_no = 4 @images = [] @file_fields_no.times do @images << Image.new end end def create @property = Property.new(params[:property]) @images = [] @file_fields_no = params[:image].length if @property.save saved_image_number = 0 # number of saved file params[:image].each_value do |file| if file[:name].size > 0 uploaded_image = file[:name] # get file contents ext = file[:name].original_filename_extension # get file extension file[:name] = "#{@property.id}-#{saved_image_number.to_s}.#{ext}" image = @property.images.build(file) image.save(uploaded_image) # call ''super'' and saves image to the disk saved_image_number += 1 end end flash[:notice] = ''Success!'' redirect_to :action => ''list'' else render :action => ''new'' end end I must admit that i don''t fully understand the need of creating ''empty'' objects in ''new'' action. If @property.save fails i don''t have any file fields in my form. Also i''m not sure what to add to @images array. As i understand, it''s used for redisplaying contents of file fields when validation fails? So should i add file or modified image object? -- Posted via http://www.ruby-forum.com/.
I''ve made file_column work with 3 files at the same time, both stored in one row. Assuming an ''applications'' table with the following fields id cover_letter resume essay applicant_id my model would be: class Application < ActiveRecord::Base file_column :cover_letter file_column :resume file_column :essay belongs_to :applicant end File_column just adds functionality onto an existing AR class, so you still get to do all of your relationshipss validations, etc. Plus it has rmagick integration so you can manipulate images if you need that functionality. It also handles those situations where save fails... So you don''t have to make your users re-upload the file. -----Original Message----- From: rails-bounces@lists.rubyonrails.org [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of szymek Sent: Friday, March 10, 2006 9:24 AM To: rails@lists.rubyonrails.org Subject: [Rails] Re: Creating multiple rows with one form Thanks for explaining. Does file_column pluing allow uploading many files in one form? Does it work with has_many/belongs_to relationship? If it does both these things, then i''ll switch immediately! :) But also it would be nice to know how to do it myself. Ok, here''s what i got now (it''s probalby 100th version :) ) in _form.rhtml: <% @file_fields_no.times do |i| %> <% @image = @images[i] %> <%= file_field "image", "name", "index" => i %><br /> <% end %> in property controller: def new @property = Property.new @file_fields_no = 4 @images = [] @file_fields_no.times do @images << Image.new end end def create @property = Property.new(params[:property]) @images = [] @file_fields_no = params[:image].length if @property.save saved_image_number = 0 # number of saved file params[:image].each_value do |file| if file[:name].size > 0 uploaded_image = file[:name] # get file contents ext = file[:name].original_filename_extension # get file extension file[:name] = "#{@property.id}-#{saved_image_number.to_s}.#{ext}" image = @property.images.build(file) image.save(uploaded_image) # call ''super'' and saves image to the disk saved_image_number += 1 end end flash[:notice] = ''Success!'' redirect_to :action => ''list'' else render :action => ''new'' end end I must admit that i don''t fully understand the need of creating ''empty'' objects in ''new'' action. If @property.save fails i don''t have any file fields in my form. Also i''m not sure what to add to @images array. As i understand, it''s used for redisplaying contents of file fields when validation fails? So should i add file or modified image object? -- Posted via http://www.ruby-forum.com/. _______________________________________________ Rails mailing list Rails@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails
I''m sooooo stupid! I forgot that in _form.rhtml i was checking name of the action to display different content for ''new'' and for ''edit'' action. I didn''t think that when "render :action => ''new''" is called from ''create'' action, the action name in _form.rhtml is still ''create'' :) But what about already uploaded images? If @property.save fails, do i have to upload them again and create "@images = Array.new(@file_fields_no) { Image.new }" again? What i should put to @images (file or image object) so the file input fields will be properly filled? -- Posted via http://www.ruby-forum.com/.
Hogan, Brian P. wrote:> I''ve made file_column work with 3 files at the same time, both stored in > one row.Hi, I''ve got a bit different situation, as i want to create many rows of the same object, each for a single file, in one form. I tried using "''index'' => number" on file_column helper method, but i get: undefined method `stringify_keys!'' for "":String -- Posted via http://www.ruby-forum.com/.
Sorry for all these stupid questions, Mark. Now that i''ve downloaded file_column plugin, i noticed that you were using file_column_field everywhere in your sample code. However i''ve learnt a lot during creating my own poor imitation of file_column plugin :) Thanks again for your patience! -- Posted via http://www.ruby-forum.com/.
Mark Reginald James
2006-Mar-11 03:35 UTC
[Rails] Re: Creating multiple rows with one form
szymek wrote:> Sorry for all these stupid questions, Mark. > > Now that i''ve downloaded file_column plugin, i noticed that you were > using file_column_field everywhere in your sample code. > > However i''ve learnt a lot during creating my own poor imitation of > file_column plugin :) > > Thanks again for your patience!No problem. Are all your earlier questions now resolved? -- We develop, watch us RoR, in numbers too big to ignore.
Well i still didn''t write the whole code for creating and editing images using this plugin, so only one new question today :) While file_column plugin correctly creates input file fields, for each file field it also creates exactly the same input hidden element with the same name and id: <input id="image_name_temp" name="image[name_temp]" type="hidden" /> <input id="image_1_name" name="image[1][name]" size="30" type="file" /> <input id="image_name_temp" name="image[name_temp]" type="hidden" /> <input id="image_2_name" name="image[2][name]" size="30" type="file" /> So it won''t pass xhtml validation, because there are many elements with the same id and it will only post one hidden element because they all have the same name. I''m not sure, but probably this field is used for checking if a file was already uploaded. If it''s true, then it won''t work correctly with many file_column fields. -- Posted via http://www.ruby-forum.com/.
New day, new question! :) I''m still struggling with the most basic code in ''create'' action of parent controller. I simplified it to only single image. def create @property = Property.new(params[:property]) if @property.save # try to save image if ok redirect_to :action => ''list'' else @image = Image.new render :action => ''new'' else @image = Image.new render :action => ''new'' end end It obviously won''t work, because if saving an image fails, it will call ''new'' action again, but the property will be already saved. So the next time, if image is saved successfully, i will get 2 property objects. Next thing is that i have the same code for else cases. Also i''m not sure what i should pass to ''new'' action so it won''t upload the image again. I can''t save images before saving property object, because i won''t have parent id. But i also can''t save property object before saving images, because if saving image fails, i will get many property objects. -- Posted via http://www.ruby-forum.com/.