[LRUG] Enforcing uniqueness
Andrew Stewart
boss at airbladesoftware.com
Fri Nov 11 06:22:54 PST 2011
Hola El Rug,
Let's say I am modelling book libraries in ActiveRecord. A library has many books and a book has many loans. A loan is "current" while the book is out of the library; and, er, not current when the book is (back) in the library.
class Library < ActiveRecord::Base
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :library
has_many :loans
has_one :current_loan, :class_name => 'Loan', :conditions => 'loans.returned_at is null'
end
class Loan < ActiveRecord::Base
belongs_to :book
end
I cannot figure out how to ensure a book can't end up with two current loans in the database. I am seeing this at the moment due to, I believe, double-click form submissions in the GUI.
Rails' uniqueness validator is vulnerable to race conditions, as my database attests. The usual answer is to apply a unique index in the database. But I want an index on the loans table like "unique(book_id) where returned_at is null" -- which isn't possible, as far as I know.
I think there are four layers where this could be tackled:
View: add client-side behaviour to prevent duplicate form submissions.
=> Mitigates the problem but doesn't really solve it.
Controller: serialise access to the action where loans are created, perhaps per library (to reduce contention).
=> Mitigates the problem but doesn't really solve it. Also I'm not sure how to implement.
Model: use a validator
=> This is what I'm already doing. It's not bullet proof.
Database: use an index
=> I don't think it's possible given my data model.
Given all of the above, I think the controller is my best bet. But I'm not sure how to do it.
Any ideas?
Cheers,
Andy Stewart
-------
http://airbladesoftware.com
More information about the Chat
mailing list