4

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

それはデータベースの観点からも理にかなっていますか?

4

0 に答える 0