Daniel Ristic
Daniel Ristic

Reputation: 710

ActiveRecord: Concurrent access between validation and writing to the database

Let's say I have on online book store whose data model lookes like that:

enter image description here

Prior to creating a new order, I want to make sure that enough items are in stock, so I have a method like this

def ensure_enough_in_stock
    errors.add(:quantity, "not enough in stock") if quantity > book.stock
end

To make sure that this method is called prior to saving in the database, I use a validate:

validate :ensure_enough_in_stock, :on => create

So to sum things up, when I create an order:

  1. the validation method is called
  2. the new order is written into the database (if validation passes)

What happens if between 1. and 2., another process (a concurrent access, another thread, ...) performs a modification on the stock attribute of the same book? Is the exception raised or not?

More generally, how to deal with the cases where something happens between validation and saving to the database?

I think that I should put a validation into the database as well, but I don't know what impact it would have on performance. Is there a clever way to deal with this kind of situation?

EDIT

Locking the transactions as explained here prevents write access to stock, but what happens if I also have a "published" attribute in the Book model, that can take the values "public" or "private", and then I want to make sure that you can't buy a book that's private.

But the same way that the stock value could be changed by an external process, the published value can be changed as well: in this case the locking would not be of any help, would it?

enter image description here

Upvotes: 4

Views: 2442

Answers (1)

Yanhao
Yanhao

Reputation: 5294

Rails usually wraps validations and saving within a transaction. So the only thing you need to do is to run the query with lock in ensure_enough_in_stock. The lock will prevent the data from being changed by other requests. See this for how to query with lock.

Upvotes: 2

Related Questions