2011-07-20 2 views
1

J'ai une application Rails 3 très simple où les utilisateurs peuvent réserver un nombre fini d'éléments homogènes pour un jour donné. J'essaye d'éviter une condition de course où deux personnes réservent le dernier article disponible un jour particulier. Le modèle (simplifié) est la suivante:Rails 3 - condition de compétition éventuelle?

class Reservation < ActiveRecord::Base 
    belongs_to :user 
    attr_accessible :date 
    MAX_THINGS_AVAILABLE = 20 

    validate :check_things_available 

    def check_things_available 
    unless things_available? errors[:base] << "No things available" 
    end 

    def things_available? 
    Reservation.find_all_by_date(date).count < MAX_THINGS_AVAILABLE 
    end   
end 

La réservation est en cours de création dans le contrôleur via current_user.reservations.build(params[:reservation])

Il se sent comme il y a une meilleure façon de faire, mais je ne peux pas à mettre doigt sur ce que c'est. Toute aide sur la façon d'empêcher l'état de la course serait grandement appréciée.

+0

Jetez un oeil à http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html – Gazler

+0

Le lien que vous avez fourni des références de mise à jour des attributs/colonnes dans un enregistrement existant, et ma condition de concurrence se produirait lorsque deux nouveaux enregistrements sont créés. Est-ce que je manque quelque chose? De plus, je ne sais pas si le verrouillage au niveau de la ligne fonctionnerait dans ce scénario, car j'utilise un nombre dérivé d'un sous-ensemble de toutes les lignes. –

+0

Je pense qu'utiliser avant les filtres est le moyen le plus facile d'aller. Si elles retournent false, la transaction entière est annulée. – Spyros

Répondre

0

Je ne sais pas que cela répond à votre question, mais il peut vous orienter vers une solution:

http://webcache.googleusercontent.com/search?q=cache:http://barelyenough.org/blog/2007/11/activerecord-race-conditions/

(le site d'origine semble être en panne de sorte que est un lien vers le cache google)

La conclusion sur cette page est que le verrouillage optimiste et le verrouillage de niveau de ligne ne sont pas des solutions pour les conditions de course sur créer, juste sur la mise à jour.

L'auteur suggère de réimplémenter find_or_create avec une contrainte db.

Une autre suggestion est que le passage du niveau d'isolation de transaction à 'sérialisable' devrait fonctionner mais il n'y a aucune information sur la façon de le faire dans Rails.

0

Il suffit d'utiliser un mécanisme de verrouillage comme redis locker

RedisLocker.new("thing_to_sell_#{@thing.id}").run do 
    current_user.create_reservation(@thing) or raise "Item already sold to another user" 
end 
Questions connexes