Topic: Need help with ajax form items, with multiple selects.

I'm using the newest version of Substruct and trying to add sizes to my items.  For some reason, when I try to pick more than one size for an item, it only saves the first one.  In looking at the COMMIT log, a hash is being generated for each selection I make, and it's only saving the first item.  Here's what my code looks like.  Also, I had to add the collection in the view (which is hideous). So I could use some help on moving this back to the controller.

edit action

 def edit
   @title = "Editing A Product"
   @product = Product.find(params[:id])
   @image = Image.new
end

save action

def save
    # If we have ID param this isn't a new product
    if params[:id]
      @new_product = false
      @title = "Editing Product"
      @product = Product.find(params[:id])
      @size = Size.find(:all)
    	@product.sizes = Size.find(params[:size_ids]) if params[:size_ids]
    else
      @new_product = true
      @title = "New Product"
      @product = Product.new()
    end
    @product.attributes = params[:product]
    @size = Size.find(:all)
  	@product.sizes = Size.find(params[:size_ids]) if params[:size_ids]
		if @product.save
			# Save product tags
			# Our method doesn't save tags properly if the product doesn't already exist.
			# Make sure it gets called after the product has an ID
			@product.tag_ids = params[:product][:tag_ids] if params[:product][:tag_ids]
      # Build product images from upload
      image_errors = []
      unless params[:image].blank?
  			params[:image].each do |i|
          if i[:image_data] && !i[:image_data].blank?
            new_image = Image.new
            logger.info i[:image_data].inspect
            new_image.uploaded_data = i[:image_data]
            new_image.description = i[:image_description]
            if new_image.save
              @product.images << new_image
            else
              image_errors.push(new_image.filename)
            end
          end
        end
      end

      # Build downloads from form
      download_errors = []
      unless params[:download].blank?
  			params[:download].each do |i|
          if i[:download_data] && !i[:download_data].blank?
            new_download = Download.new
            logger.info i[:download_data].inspect
          
            new_download.uploaded_data = i[:download_data]
            if new_download.save
              new_download.product = @product
            else
              download_errors.push(new_download.filename)
            end
          end
        end
      end

      # Build variations from form
      if !params[:variation].blank?
        params[:variation].each do |v|
          variation = @product.variations.find_or_create_by_id(v[:id])
          variation.attributes = v
          variation.sizes = Size.find(params[:size_ids]) if params[:size_ids]
          variation.save
          @product.variations << variation
        end
      end
      
      flash[:notice] = "Product '#{@product.name}' saved."
      if image_errors.length > 0
        flash[:notice] += "<b>Warning:</b> Failed to upload image(s) #{image_errors.join(',')}. This may happen if the size is greater than the maximum allowed of #{Image::MAX_SIZE / 1024 / 1024} MB!"
      end
      if download_errors.length > 0
        flash[:notice] += "<b>Warning:</b> Failed to upload file(s) #{download_errors.join(',')}."
      end
      redirect_to :action => 'edit', :id => @product.id
    else
			@image = Image.new
			if @new_product
        render :action => 'new' and return
      else
        render :action => 'edit' and return
      end
    end    
  end

form.rhtml

<div id="variation_container">
  <%= render :partial => 'variation', :collection => @product.variations %>
</div>

variation partial

<div class="variation">
	<input type="hidden" name="variation[][id]" value="<%= variation.id %>" />
	<div class="float">
		<%= make_label('Name', true) %>
		<%= text_field_tag('variation[][name]', variation.short_name, :size => 30, :class => 'textInput') %>
		<br/>
		<span class="info">ie: Red XXL</span>
	</div>
	<div class="float">
		<%= make_label('Product Code', true) %>
		<%= text_field_tag('variation[][item]', variation.item, :size => 10, :class => 'textInput') %>
	</div>
	<div class="float">
		<%= make_label('Price') %>
		<%= text_field_tag('variation[][price]', variation.price, :size => 6, :class => 'textInput numeric') %>
	</div>
	<div class="float">
		<%= make_label('Quantity') %>
		<%= text_field_tag('variation[][quantity]', variation.quantity, :size => 6, :class => 'textInput numeric') %>
	</div>
	<div class="float">
		<%= make_label('Size') %>
		<% @size = Size.find(:all) %>
		<% @selected = variation.sizes.collect { |cat| cat.id.to_i } %>
		<select id="sizes" name="variation[][size_ids][]" multiple="multiple" size="5", :class => 'textInput'>
		<%= options_from_collection_for_select(@size, "id", "name", @selected) %>
		</select>
	</div>
	<!-- remove link -->
	<div style="float:right;margin-top:20px;">
		<%= 
			link_to_remote image_tag("icons/png-24/16-em-cross.png", :plugin => 'substruct', :alt => 'Delete'),
	    	{
					:url => { :action => "remove_variation_ajax", :id => variation.id },
					:loading => "$('remove_variation_link_#{variation.id}').hide(); $('variation_indicator_#{variation.id}').show();",
	    		:complete => "$('remove_variation_link_#{variation.id}').up('.variation').remove();"
				},
				:id => "remove_variation_link_#{variation.id}"
		%>
		<%= image_tag("/indicator.gif", :plugin => 'substruct', :style => 'display:none;', :id => "variation_indicator_#{variation.id}") %>
	</div>
	<div class="clear"></div>
</div>

The issue is with the code from this line...

<%= options_from_collection_for_select(@size, "id", "name", @selected) %>

The output of a save looks like this...

Processing ProductsController#save (for 127.0.0.1 at 2008-09-16 15:49:53) [POST]
  Session ID: 554d8bcf1aab0fe069f8f445e8b92716
  Parameters: {"variation"=>[{"name"=>"asdfasd", "code"=>"dfd", "price"=>"10.2", "quantity"=>"12", "id"=>"1221593973", "size_ids"=>["2"]}, {"name"=>"sdff", "code"=>"dafdsf", "price"=>"10.2", "quantity"=>"0", "id"=>"1221593980", "size_ids"=>["3"]}, {"size_ids"=>["5"]}, {"size_ids"=>["9"]}], "commit"=>"Save This Product", "product"=>{"name"=>"Ladies Fleece Jacket", "size_width"=>"0", "weight"=>"0", "code"=>"7420", "date_available(1i)"=>"2008", "size_height"=>"0", "description"=>"Warm up to comfort and style in the Arctic women’s 10.2 oz. heavyweight 100% spun polyester Anti-Pilling PANDA FLEECE jacket. Featuring nylon panels on the front and back yoke, back forearms and along the bottom. Accented with chest and side zippered pockets, elastic-bound cuffs and the EMB-AXS system for clean embroidery. Adjustable drawstring bottom with cord locks provides a custom fit. Slight drop tail.", "date_available(2i)"=>"9", "date_available(3i)"=>"15", "tag_ids"=>["", "3"], "is_discontinued"=>"0", "related_product_ids"=>["", "", "", "", ""], "size_depth"=>"0"}, "action"=>"save", "id"=>"1221483855", "controller"=>"admin/products", "image"=>[{"image_description"=>"", "image_data_temp"=>"", "image_data"=>""}, {"image_description"=>"", "image_data_temp"=>"", "image_data"=>""}]}

If you see this variation has 3 size_id hashes, instead of 1 size_ids array.

{"name"=>"sdff", "code"=>"dafdsf", "price"=>"10.2", "quantity"=>"0", "id"=>"1221593980", "size_ids"=>["3"]}, {"size_ids"=>["5"]}, {"size_ids"=>["9"]}]

Any help you can provide is greatly appreciated!

Thanks,
Zack

Last edited by zreed20 (2008-09-16 12:03:41)

But they that wait upon the Lord shall renew their strength

Re: Need help with ajax form items, with multiple selects.

This is related to forms not being serialized correctly with Prototype. I had this problem as well, and switches to Jquery for this reason. You might also make sure that you're using the latest Rails 2.1.1 - that might make a difference.

Ryan Heneise  |  Art of Mission  |  Now with extra-strong Donor Tools mojo

Re: Need help with ajax form items, with multiple selects.

I think this ticket talks about this issue: http://dev.rubyonrails.org/ticket/6645

Also, forgot to mention that there is JRails, a plugin to easily replace Prototype with Jquery: http://ennerchi.com/projects/jrails

Ryan Heneise  |  Art of Mission  |  Now with extra-strong Donor Tools mojo

Re: Need help with ajax form items, with multiple selects.

Thanks ryenski!

I haven't tried rolling jquery into any of my Rails apps yet.  I am running Rails 2.1.1, so that won't be the cure for me in this occasion, but thanks for the suggestion smile

I'm definitely going to check out JRails, but I'd hate to add a new plugin in for just one goofy action if I don't have to.  I just wonder if there's a better way to structure the code, so Prototype can serialize it?

**UPDATE**
I just installed the JRails plugin, and unfortunately that didn't fix it either...

Thanks again,
Zack

Last edited by zreed20 (2008-09-17 11:13:49)

But they that wait upon the Lord shall renew their strength