From 8deb4ef9d4de38ebcddcd2c83ad3c56d59baf748 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Tue, 30 Jun 2015 12:50:52 +1000 Subject: [PATCH] When encountering StaleObjectError when checking out, retry --- app/controllers/checkout_controller.rb | 15 +++++++++- spec/controllers/checkout_controller_spec.rb | 30 ++++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb index 11be28ef04..f13d28d94e 100644 --- a/app/controllers/checkout_controller.rb +++ b/app/controllers/checkout_controller.rb @@ -23,7 +23,7 @@ class CheckoutController < Spree::CheckoutController return if redirect_to_paypal_express_form_if_needed end - if @order.next + if advance_order_state(@order) state_callback(:after) else if @order.errors.present? @@ -83,6 +83,19 @@ class CheckoutController < Spree::CheckoutController params[:order] end + def advance_order_state(order) + result = false + tries = 3 + + begin + result = order.next + rescue ActiveRecord::StaleObjectError + retry unless (tries -= 1).zero? + end + + result + end + def update_failed clear_ship_address diff --git a/spec/controllers/checkout_controller_spec.rb b/spec/controllers/checkout_controller_spec.rb index 0499febfc9..dd9e44c5be 100644 --- a/spec/controllers/checkout_controller_spec.rb +++ b/spec/controllers/checkout_controller_spec.rb @@ -55,7 +55,7 @@ describe CheckoutController do it "doesn't copy the previous shipping address from a pickup order" do old_order = create(:order, bill_address: create(:address), ship_address: create(:address)) Spree::Order.stub_chain(:order, :where, :where, :limit, :detect).and_return(old_order) - controller.send(:find_last_used_addresses, "email").last.should == nil + controller.send(:find_last_used_addresses, "email").last.should == nil end describe "building the order" do @@ -69,7 +69,7 @@ describe CheckoutController do get :edit assigns[:order].ship_address.address1.should be_nil end - + it "clears the ship address when re-rendering edit" do controller.should_receive(:clear_ship_address).and_return true order.stub(:update_attributes).and_return false @@ -119,6 +119,32 @@ describe CheckoutController do response.status.should == 200 response.body.should == {path: spree.order_path(order)}.to_json end + + describe "stale object handling" do + it "retries when a stale object error is encountered" do + order.stub(:update_attributes).and_return true + controller.stub(:state_callback) + + # The first time, raise a StaleObjectError. The second time, succeed. + order.stub(:next).once. + and_raise(ActiveRecord::StaleObjectError.new(Spree::Variant.new, 'update')) + order.stub(:next).once do + order.update_column :state, 'complete' + true + end + + xhr :post, :update, order: {}, use_route: :spree + response.status.should == 200 + end + + it "tries a maximum of 3 times before giving up and returning an error" do + order.stub(:update_attributes).and_return true + order.stub(:next) { raise ActiveRecord::StaleObjectError.new(Spree::Variant.new, 'update') } + + xhr :post, :update, order: {}, use_route: :spree + response.status.should == 400 + end + end end describe "Paypal routing" do