Greetings to all Ruby on Rails enthusiasts. In this topic I would like to write about a gotcha you may find as a Ruby on Rails developer while using acts_as_state_machine plugin in your Ruby on Rails applications.

Lets imagine you’re developing a Ruby on Rails application which is e-marketplace solution for selling all kinds of products. You have a Product model and two aasm states:

aasm_state :available
aasm_state :sold

and of course a transition method for changing state from available to sold:

aasm_state :sell do
transitions :to => :sold, :from => [:available]
end

The Ruby on Rails gotcha I am going to write about is that acts_as_state_machine is not concurrent.
Imagine a situation where there is only one product and two users are clicking on a “buy” button simultaneously. Assuming you have something like this in your controller:

def sell
@product = Product.find(params[:id])
@product.buy!
redirect_to(products_path)
end

Then your Ruby on Rails application will execute things twice, thus it will send two confirmation emails to your client. There is no need to tell you, why sending two emails in this case may be a bad case – if you’re revving money account or transferring things to twin accounts, then this is a big deal, big issue for your Ruby on Rails e-marketplace. So with what kind of solution you could come as a Ruby on Rails developer?

One solution you could come with, as a Ruby on Rails developer is to wrap in controller code in a transaction like this:

def sell
Product.transaction do
@product = Product.find(params[:id], :lock => true)
@product.buy!
end
redirect_to(products_path)
end

So, as you can see, it is not that hard to fix this problem, but tracking it may be a real pain. Therefore it is nice to be aware of such gotcha, as a Ruby on Rails developer to prevent such situation occurring in your Ruby on Rails application, like it has occurred in this RoR e-marketplace example application, I’ve used to explain the problem.