rails-単純なロックを実装して、ユーザーが同じデータを同時に編集できないようにします
-
05-07-2019 - |
質問
別のユーザーが編集している間、ユーザーがデータを編集できないようにする必要があるアプリがあります。私はそれを行うための最良の方法を考えているので、アイデアを求めていました。これまで、キーと値のペアでアプリケーション全体の構成をデータベースに保存する設定モデルを作成しました。したがって、ロックのために、LOCKED_TABLE_UIDと呼ばれる設定インスタンスがあり、テーブルを編集しているユーザーのuser_idまたはテーブルが空いている場合はnull(nil)を保存しました。
>> lock = Setting.find_by_key('LOCKED_TABLE_UID')
次に、ロックを取得および解放するために、アプリケーションコントローラーに2つのメソッドを実装しました。
# 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
私が望んでいるのは、次のようなロックメカニズムを含む何らかの種類のブロックコードを作成することです。
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
これについて助けていただければ幸いです-しかし、私はそれをすべて達成する方法について他の提案や、私が見落としていたかもしれないことを受け入れています。このロックはアトミックである必要はありませんが、かなり基本的で最も重要です-動作すること:) ありがとう。
解決
もうすぐです。 require_lockingを作成しますか?あなたが合うと思うアクション。次に、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
他のヒント
ActiveRecordの組み込みロック機能を見ましたか?
このアイデアは気に入っていますが、ソリューションに大きな問題があります。テーブル全体のロックを取得および解放しているということです。
大丈夫な非常に小さなアプリの場合、たとえば「PRODUCTS」テーブルにアクセスしようとして数千人のユーザーがいて、誰かが自分の製品とはまったく関係のないエントリを編集しているために待たなければならない場合を想像してください。
よりきめの細かいアプローチを使用して、テーブルではなく特定の行をロックすることもできます。ロックには、テーブル名、行ID、ユーザーIDが含まれます。
acts_as_lockable_by gemは、あなたが求めていることを、より簡単な用語でより少ないコードで正確に実行していると思います。レールやベアルビープロジェクトと簡単に統合できます。
このgemを使用すると、アトミックな lock
、 unlock
、および renew_lock
メソッドを取得できます。また、自動期限切れの ttl
ロックが発生するため、たわごとがファンに当たり、リソースのロックを解除できなかった場合、自動的にロックが解除されます!