diff --git a/app/controllers/spree/admin/products_controller_decorator.rb b/app/controllers/spree/admin/products_controller_decorator.rb index af0e8cda62..3f5e092773 100644 --- a/app/controllers/spree/admin/products_controller_decorator.rb +++ b/app/controllers/spree/admin/products_controller_decorator.rb @@ -15,11 +15,10 @@ Spree::Admin::ProductsController.class_eval do end def bulk_update - @collection_hash = Hash[params[:_json].each_with_index.map { |p,i| [i,p] }] - @collection_attributes = { :collection_attributes => @collection_hash } - @product_set = Spree::ProductSet.new(@collection_attributes) + collection_hash = Hash[params[:_json].each_with_index.map { |p,i| [i,p] }] + product_set = Spree::ProductSet.new() - if @product_set.save + if product_set.save(collection_hash) redirect_to bulk_index_admin_products_url :format => :json else render :nothing => true diff --git a/app/models/spree/product_set.rb b/app/models/spree/product_set.rb index 81041ffb66..fb9f3db0c9 100644 --- a/app/models/spree/product_set.rb +++ b/app/models/spree/product_set.rb @@ -1,7 +1,37 @@ class Spree::ProductSet < ModelSet def initialize(attributes={}) - super(Spree::Product, Spree::Product.all, + product_ids = attributes[:collection_attributes].each_value.map{ |p| p["id"] } if attributes[:collection_attributes] + super(Spree::Product, (product_ids ? Spree::Product.select{ |p| p.id.in? product_ids } : Spree::Product.all ), proc { |attrs| attrs[:product_id].blank? }, attributes) end + + # A separate method of updating products was required due to an issue with the way Rails' assign_attributes and updates_attributes behave when delegated attributes of a nested + # object are updated via the parent object (ie. price of variants). Updating such attributes by themselves did not work using: + # product.update_attributes( { variants_attributes: [ { id: y, price: xx.x } ] } ) + # and so an explicit call to update attributes on each individual variant was required. ie: + # variant.update_attributes( { price: xx.x } ) + def update_attributes(attributes) + e = @collection.detect { |e| e.id.to_s == attributes[:id].to_s && !e.id.nil? } + if e.nil? + @klass.new(attributes).save unless @reject_if.andand.call(attributes) + else + e.update_attributes(attributes.except(:id,:variants_attributes)) and (attributes[:variants_attributes] ? update_variants_attributes(e,attributes[:variants_attributes]) : true ) + end + end + + def update_variants_attributes(product,variants_attributes) + variants_attributes.each do |attributes| + e = product.variants.detect { |e| e.id.to_s == attributes[:id].to_s && !e.id.nil? } + if !e.nil? + e.update_attributes(attributes.except(:id)) + end + end + end + + def save(collection_hash) + collection_hash.each_value.all? do |product_attributes| + update_attributes(product_attributes) + end + end end \ No newline at end of file diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index c68a5657ad..abed3cc2cf 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -232,6 +232,26 @@ feature %q{ page.should have_field "variant_on_hand", with: "10" end + scenario "updating delegated attributes of variants in isolation" do + p = FactoryGirl.create(:product) + v = FactoryGirl.create(:variant, product: p, price: 3.0) + + login_to_admin_section + + visit '/admin/products/bulk_index' + + page.should have_field "variant_price", with: "3.0" + + fill_in "variant_price", with: "10.0" + + click_button 'Update' + page.find("span#update-status-message").should have_content "Update complete" + + visit '/admin/products/bulk_index' + + page.should have_field "variant_price", with: "10.0" + end + scenario "updating a product mutiple times without refresh" do p = FactoryGirl.create(:product, name: 'original name') login_to_admin_section