I''m trying to provide our customers with a page where they can add up to 20 items to their cart in one form. The form simply has 20 rows with each row containing a text input for product code and a text input for quantity. I''ve tried having the controller create an array that has an object for each row by looping through something like: @new_items[1] = Cart.new and the controller is happy with that, but the template isn''t--it gives an error like "@new_items[1] is not allowed as an instance variable name". I can get the whole thing working if I use non-model form objects in the template, but then I lose the Rails error magic where it highlights any errant fields and gives a message. Why can I create Cart objects within an array in the controller, but not use them in the template. Or am I going about this completely wrong?? Any help is appreciated greatly. -- Posted via http://www.ruby-forum.com/.
Mark Reginald James
2006-Feb-04 06:54 UTC
[Rails] Re: how to add multiple new records from one form
Shawn Goble wrote:> I''m trying to provide our customers with a page where they can add up to > 20 items to their cart in one form. The form simply has 20 rows with > each row containing a text input for product code and a text input for > quantity. > > I''ve tried having the controller create an array that has an object for > each row by looping through something like: > > @new_items[1] = Cart.new > > and the controller is happy with that, but the template isn''t--it gives > an error like "@new_items[1] is not allowed as an instance variable > name".Perhaps: <% for i in 1..20 do %> <%= text_field :new_items, :product_code, :index => i %> <%= text_field :new_items, :quantity, :index => i %> <% end %> case request.method when :get then @new_items = Array.new(20) { Cart.new } when :post all_valid = true @new_items = [] params[:new_items].each_value { |p| @new_items << (c=Cart.new(p)); all_valid &&= c.valid? } if !@new_items.empty? && all_valid @user.items << @new_items @user.save(false) redirect_to :action => ''show_cart'' else flash[:error] = ''No items entered'' if @new_items.empty? (20-@new_items.length).times { @new_items << Cart.new } end end -- We develop, watch us RoR, in numbers too big to ignore.
Woei Shyang
2006-Feb-04 10:28 UTC
[Rails] Re: how to add multiple new records from one form
Mark Reginald James wrote:> Shawn Goble wrote: >> and the controller is happy with that, but the template isn''t--it gives >> an error like "@new_items[1] is not allowed as an instance variable >> name". > > Perhaps: > > <% for i in 1..20 do %> > <%= text_field :new_items, :product_code, :index => i %> > <%= text_field :new_items, :quantity, :index => i %> > <% end %> >Hi Mark, My query with this is, would Rails look at the number enclosed within the square brackets and subsequently clobber records with id ranging from [1] to [20]? The confusion stemmed about from the fact that if you provide blank brackets when rendering an edit form, such as: <% for @comment in @post.comments %> <%= text_field ''comment[]'', ''author'' %> <%= text_field ''comment[]'', ''body'' %> <% end %> It will also generate similar looking HTML tags, and hence in that case the number enclosed within the square brackets do have some significance. Thanks. -- Posted via http://www.ruby-forum.com/.
Mark Reginald James
2006-Feb-04 10:50 UTC
[Rails] Re: how to add multiple new records from one form
Woei Shyang wrote:>><% for i in 1..20 do %> >><%= text_field :new_items, :product_code, :index => i %> >><%= text_field :new_items, :quantity, :index => i %> >><% end %>> My query with this is, would Rails look at the number enclosed within > the square brackets and subsequently clobber records with id ranging > from [1] to [20]? > > The confusion stemmed about from the fact that if you provide blank > brackets when rendering an edit form, such as: > > <% for @comment in @post.comments %> > <%= text_field ''comment[]'', ''author'' %> > <%= text_field ''comment[]'', ''body'' %> > <% end %> > > It will also generate similar looking HTML tags, and hence in that case > the number enclosed within the square brackets do have some > significance.While the parameter hash would be similar, with id rather than index keys, you would handle it differently in the controller. The Agile book suggests Cart.update(params[:new_items].keys, params[:new_items].values) In the code I''ve given, the keys aren''t even looked at. New records with new ids are created based on the hash values. Looking over the code I see a few errors: The save of @user is not needed, and flash.now should be used, not just flash. Also, for greater efficiency, each new item should be instantiated via @user.items.build(p), then, if all pass validation, saved using save(false), avoiding a second validation. -- We develop, watch us RoR, in numbers too big to ignore.
Shawn Goble
2006-Feb-04 15:50 UTC
[Rails] Re: how to add multiple new records from one form
Mark Reginald James wrote:> > Perhaps: > > <% for i in 1..20 do %> > <%= text_field :new_items, :product_code, :index => i %> > <%= text_field :new_items, :quantity, :index => i %> > <% end %> > > > case request.method > when :get then @new_items = Array.new(20) { Cart.new } > when :post > all_valid = true > @new_items = [] > params[:new_items].each_value { |p| @new_items << (c=Cart.new(p)); > all_valid &&= c.valid? } > if !@new_items.empty? && all_valid > @user.items << @new_items > @user.save(false) > redirect_to :action => ''show_cart'' > else > flash[:error] = ''No items entered'' if @new_items.empty? > (20-@new_items.length).times { @new_items << Cart.new } > end > endIs this method going to flow any validation errors back to the form though? If it was just one new item on the form you could use: <%= error_messages_for ''new_items'' %> but I''m not clear on whether that would work with this method. Doesn''t it end up just like it would using non-model objects on the form and placing the data into Cart objects in the controller? Works, but the form doesn''t show the validation messages. -- Posted via http://www.ruby-forum.com/.
Mark Reginald James
2006-Feb-04 17:16 UTC
[Rails] Re: how to add multiple new records from one form
Shawn Goble wrote:> Mark Reginald James wrote: >> [CODE] > > Is this method going to flow any validation errors back to the form > though? If it was just one new item on the form you could use: > > <%= error_messages_for ''new_items'' %> > > but I''m not clear on whether that would work with this method. Doesn''t > it end up just like it would using non-model objects on the form and > placing the data into Cart objects in the controller? Works, but the > form doesn''t show the validation messages.All fields with errors will be highlighted, but to get the text messages you''ll need something like: <% for i in 1..20 @item = @new_items[i-1] %> Item <%= i %>: <%= error_messages_for :item %> <% end %> -- We develop, watch us RoR, in numbers too big to ignore.
Shawn Goble
2006-Feb-06 16:51 UTC
[Rails] Re: how to add multiple new records from one form
Mark Reginald James wrote:> case request.method > when :get then @new_items = Array.new(20) { Cart.new } > when :postThis still seems not to work. If in the controller I use: @new_items = Cart.new then the :index in the template seems to work correctly (even though I''ve only created one object in the controller). It will even save the information to the database correctly using that method. The downside is that I still can''t get validation error information back to the form. If however, I do as you suggest (which does seem to make more sense) and use: @new_items = Array.new(20) { Cart.new } I get the error "undefined method `product_id'' for #<Array:0x55dae60>", which seems to suggest that :index isn''t actually letting me reference an array but creating one after the fact from a single object. (Incidentally, if I use @new_items = Cart.new and then after :post I eventually use something like @new_items = Cart.create(items), I get the same error "undefined method `product_id'' for #<Array:0x55dae60>" in the template.) Thanks for the help so far, I''ve at least learned something about the :index parameter. -- Posted via http://www.ruby-forum.com/.
Mark Reginald James
2006-Feb-09 11:29 UTC
[Rails] Re: how to add multiple new records from one form
Shawn Goble wrote:> If in the controller I use: > > @new_items = Cart.new > > then the :index in the template seems to work correctly (even though > I''ve only created one object in the controller). It will even save the > information to the database correctly using that method. The downside > is that I still can''t get validation error information back to the form. > > If however, I do as you suggest (which does seem to make more sense) and > use: > > @new_items = Array.new(20) { Cart.new } > > I get the error "undefined method `product_id'' for #<Array:0x55dae60>", > which seems to suggest that :index isn''t actually letting me reference > an array but creating one after the fact from a single object.Yes, sorry, the :index parameter does not do what I thought it did. It replicates form fields and parameters from a single model instance, which is not useful for the multiple instances with validation errors situation you are looking for. You may be able to make it work using some trick like: <% @new_items.each_with_index do |@cart, i| %> <%= text_field :cart, :product_id, :name => "cart[#{i}][product_id]" %> <% end %> -- We develop, watch us RoR, in numbers too big to ignore.