[LRUG] Enforcing uniqueness

Viktor Tron viktor.tron at gmail.com
Fri Nov 11 08:46:14 PST 2011


Roland, splitting past vs current loans don't solve the partial index  
problem: assuming future loans on
the same book can be entered, book_id will only be unique for 'active'  
loans (uniqueness would have to be scoped
for active=true or returned_at=null).

What I would do is model books currently on loan separately.

class Book < ActiveRecord::Base
     belongs_to :library
     has_many :loans
     has_one  :current_loan
end


class Loan < ActiveRecord::Base
     belongs_to :book
end

class CurrentLoan < ActiveRecord::Base
     belongs_to :book
     belongs_to :loan

     validates :book_id, :uniqueness => true
end

The actual borrow/return of the book corresponds with create/destroy of a  
CurrentLoan instance.
This is very intuitive to me since.
Loans would have request and (relative) due dates while borrow/return  
dates would be recorded
as create/destroy callbacks on CurrentLoan.

hth

On Fri, 11 Nov 2011 14:37:26 -0000, Roland Swingler  
<roland.swingler at gmail.com> wrote:

> Could you split Loans into current loans and past loans, and have a
> table for each? Current Loans can then have a unique index on the
> book_id column.
>
> Roland
>
> On Fri, Nov 11, 2011 at 2:22 PM, Andrew Stewart
> <boss at airbladesoftware.com> wrote:
>> 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
>> _______________________________________________
>> Chat mailing list
>> Chat at lists.lrug.org
>> http://lists.lrug.org/listinfo.cgi/chat-lrug.org
>>
> _______________________________________________
> Chat mailing list
> Chat at lists.lrug.org
> http://lists.lrug.org/listinfo.cgi/chat-lrug.org



More information about the Chat mailing list