Rails アプリで競合状態の問題が発生しています。説明する前に、少し(簡略化された)コードを次に示します。
class Message < ActiveRecord::Base
belongs_to :question
end
class Question < ActiveRecord::Base
has_many :messages
def create_or_update_sending_message
sending_message = messages.detect {|m| m.status == 'sending'}
sending_message ||= messages.create :status => 'sending'
sending_message
end
def validate
errors.add_to_base('cannot have multiple sending messages') if messages.select {|m| m.status == 'sending'}.count > 1
end
end
何が起こっているかcreate_or_update_sending_message
というと、2 つのプロセスから呼び出されています。どちらもメッセージ コレクションを空と見なすため、どちらも新しいメッセージを作成します。次に、3 番目のプロセスが質問を読み込み、変更し、保存しようとすると、実際の問題が発生した場所ではない場所にエラーがスローされます。
ゼロから設計している場合、これを回避するいくつかの方法を考えることができますが、残念ながらcreate_or_update_sending_message
レガシー コードが深すぎて実用的ではありません。
質問モデルに対して楽観的ロックを有効にしました。質問が保存されていないため、役に立ちません。メッセージのみが保存されます。
メッセージの作成の保存を防ぐために、質問に対して楽観的ロックを使用する方法はありますか? だから、それは次のようになります
def create_or_update_sending_message
self.optimistically_lock do |lock|
sending_message = messages.detect {|m| m.status == 'sending'}
sending_message ||= messages.create_with_optimistic_lock lock, :status => 'sending'
sending_message
end
end
それはデータベースの観点からも理にかなっていますか?