Skip to content

Commit

Permalink
Implement a state lock version to prevent race conditions in checkout…
Browse files Browse the repository at this point in the history
… controller. refs spree#4190
  • Loading branch information
Jeff Dutil authored and Jeff Dutil committed Oct 21, 2014
1 parent 9da5d09 commit 0fe6c9d
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddStateLockVersionToOrder < ActiveRecord::Migration
def change
add_column :spree_orders, :state_lock_version, :integer, default: 0, null: false
end
end
5 changes: 4 additions & 1 deletion core/lib/spree/permitted_attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ module PermittedAttributes
state: [:name, :abbr]
]

@@checkout_attributes = [:email, :use_billing, :shipping_method_id, :coupon_code, :special_instructions]
@@checkout_attributes = [
:coupon_code, :email, :shipping_method_id, :special_instructions,
:state_lock_version, :use_billing
]

@@customer_return_attributes = [:stock_location_id, return_items_attributes: [:id, :inventory_unit_id, :return_authorization_id, :returned, :pre_tax_amount, :acceptance_status, :exchange_variant_id]]

Expand Down
9 changes: 9 additions & 0 deletions frontend/app/controllers/spree/checkout_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ def load_order_with_lock
@order = current_order(lock: true)
redirect_to spree.cart_path and return unless @order

@order.with_lock do
if params[:order] && params[:order][:state_lock_version]
unless @order.state_lock_version == params[:order][:state_lock_version].to_i
redirect_to checkout_state_path(@order.state) and return
end
@order.increment!(:state_lock_version)
end
end

if params[:state]
redirect_to checkout_state_path(@order.state) if @order.can_go_to_state?(params[:state]) && !skip_state_validation?
@order.state = params[:state]
Expand Down
9 changes: 5 additions & 4 deletions frontend/app/views/spree/checkout/edit.html.erb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<div id="checkout" data-hook>
<div id="checkout" data-hook>
<%= render :partial => 'spree/shared/error_messages', :locals => { :target => @order } %>

<div class="row" data-hook="checkout_header">
<h1 class="columns three alpha" data-hook="checkout_title"><%= Spree.t(:checkout) %></h1>
<div class="columns thirteen omega" data-hook="checkout_progress"><%= checkout_progress %></div>
</div>

<div class="row" data-hook="checkout_content">
<div class="columns <%= if @order.state != 'confirm' then 'alpha twelve' else 'alpha omega sixteen' end %>" data-hook="checkout_form_wrapper">
<%= form_for @order, :url => update_checkout_path(@order.state), :html => { :id => "checkout_form_#{@order.state}" } do |form| %>
Expand All @@ -15,9 +15,10 @@
<%= form.text_field :email %>
</p>
<% end %>
<%= form.hidden_field :state_lock_version %>
<%= render @order.state, :form => form %>
<% end %>
</div>
</div>
<% if @order.state != 'confirm' %>
<div id="checkout-summary" data-hook="checkout_summary_box" class="columns omega four">
<%= render :partial => 'summary', :locals => { :order => @order } %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
it "should associate the order with a user" do
order.user = nil
order.should_receive(:associate_user!).with(user)
spree_get :edit, {}, :order_id => 1
spree_get :edit, {}, order_id: 1
end
end
end
Expand Down

0 comments on commit 0fe6c9d

Please sign in to comment.