次のシナリオがあるとします。
class MyModel < ActiveRecord::Base
after_save :throw_after_save
after_commit :throw_after_commit
private
def throw_after_save
raise "raising on after_save"
end
def throw_after_commit
raise "raising on after_commit"
end
end
class MyController < ApplicationController
def callback
begin
MyModel.new(params).save
rescue
flash[:alert] = "Failed persisting to external system. Try again."
Airbrake.notify(
error_class: "External System Persistence",
error_message: "External System Persistence: Failed to persist data",
parameters: params
)
end
redirect_to root_path
end
end
外部システムからコールバックを取得します (ユーザーがデータを入力し、アカウントの属性の一時的なセットを作成します)。
私たちへのコールバックが行われた後、いくつかのデータをローカルに保持したいと仮定しましょう。このデータが永続化された後、外部システムを呼び出して、アカウント作成プロセスを完了させたいと考えています。外部システムは、ローカルに保持する必要があるいくつかの追加データとともに、成功を通知する結果を返します。また、一部の例外的なケースでは、リモート システムでの永続化が正常に行われないこともわかっています (システムが利用できない場合や、システム側で問題が発生した場合など)。
目的は、成功だけでなく外部永続化の例外も捕捉し、それに応じて行動することです。成功した場合、すべてがうまくいきます。追加のデータはローカルに保存されredirect_to root_path
ます。ただし、例外の場合は、これをユーザーに示したいと思います (おそらく、 aflash[:alert]
をビューに表示するように設定します)。
ActiveRecord::Callbacks
モデルから例外をスローafter_save
しafter_commit
、コントローラーでアラートを設定してその例外を処理し、場合によっては何らかの例外通知システム (Airbrake など) に例外を渡すために使用しようとしました。の場合after_save
、例外はモデルによってスローされ、コントローラーによってキャッチされますが、レコードは保存されません (また、外部システムで例外が発生した場合でも、部分的なデータを保存する必要があります。これは受け入れられません)。 )。の場合after_commit
、例外はスローされず、コントローラーによって取得されませんが、部分的なレコードは永続化されます。これは、ユーザーに例外を通知できないことを意味します (何らかの通知プッシュ メカニズムを実装しない限り、これはやり過ぎです)。
結局のところ、 のモデルにエラーを設定できafter_save
ます。これは素晴らしいことです。しかし、これはこの種のシナリオを処理するための良い一般的なパターンですか?