2009-11-26 7 views
4

J'ai une application où je dois empêcher les utilisateurs de données d'édition alors qu'il est en cours d'édition par un autre utilisateur. J'essaie de penser à la meilleure façon de le faire et je voulais demander des idées. Jusqu'à présent, j'ai créé un modèle de paramètres qui stocke la configuration à l'échelle de l'application sur la base de données dans les paires clé/valeur. Donc, pour le verrou, j'ai une instance de paramètres appelée LOCKED_TABLE_UID, et elle stocke le user_id de l'utilisateur éditant la table ou null (nil) si la table est libre.rails - mettant en oeuvre une serrure simple pour empêcher de modifier les mêmes données en même temps que l'utilisateur

>> lock = Setting.find_by_key('LOCKED_TABLE_UID') 

Ensuite, je mis en œuvre 2 méthodes dans mon contrôleur d'application pour acquérir et libérer le verrou:

# current_user returns the user currently logged in 
def acquire_lock 
    lock = Setting.find_by_key("LOCKED_TABLE_UID") 
    if lock.value 
    # if lock taken, see if it's the current_user or someone else 
    if lock.value.to_i == current_user.id.to_i 
     return true 
    else 
     return false 
    end 
    else 
    # lock is free, assign it to this user 
    lock.value = current_user.id 
    return true if lock.save 
    end 
end 

def release_lock 
    lock = Setting.find_by_key("LOCKED_TABLE_UID") 
    if lock.value 
    # the lock belongs to current_user, so he can release it 
    if lock.value.to_i == current_user.id.to_i 
     lock.value = nil 
     return true if lock.save 
    else 
     # not your lock, go away 
     return false 
    end 
    else 
    # lock is free, quit bugging 
    return true 
    end 
end 

Ce que je veux est de créer une sorte de code de bloc qui contient le mécanisme de verrouillage, quelque chose comme ceci:

def some_crud_action 
    requires_locking do |lock| 
    if lock 
     # do some CRUD stuff here 
    else 
     # decline CRUD and give some error 
    end 
    end 
end 

Je vous en serais reconnaissant de l'aide à ce sujet - mais je suis aussi ouvert à d'autres suggestions sur la façon d'accomplir tout cela, ou certaines choses que je peux avoir oublié. Ce verrou ne doit pas être atomique, mais plutôt basique et le plus important - que cela fonctionne :) merci.

Répondre

1

Vous y êtes presque. Créez votre require_locking? l'action comme bon vous semble. Puis le traiter avec un before_filter.

before_filter :requires_locking?, :only => [:update, :destroy] 
after_filter :release_lock, :only => [:update, :destroy] 

def requires_locking do |lock| 
    unless acquire_lock 
     lock = Setting.find_by_key("LOCKED_TABLE_UID") 
     user_with_lock = User.find(lock.value) 
     flash[:message] = "Action denied: Table locked by: #{user_with_lock.name}" 
     redirect_to :back 
    end 
end 
7

Avez-vous vu la ActiveRecord fonction intégrée de verrouillage?

+0

Ce sont bons, mais je cherchais quelque chose de plus simple qui fournira également des informations sur l'utilisateur qui détient actuellement le verrou. – sa125

0

J'aime l'idée, mais voir un gros problème avec votre solution, et il est que vous obtenez et libérer les verrous de tables entières.

Pour une très petite application qui pourrait convenir, mais imaginez si vous avez des milliers d'utilisateurs qui tentent d'accéder, disons, à la table 'PRODUCTS' et d'attendre parce que quelqu'un modifie une entrée totalement indépendante de leurs propres produits .

Peut-être que vous pourriez avoir une approche de grain plus fin et verrouiller des lignes particulières au lieu de tables. Ensuite, le verrou comprend le nom de la table, l'ID de la ligne et l'ID de l'utilisateur.