1

次のシナリオがあるとします。

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_saveafter_commit、コントローラーでアラートを設定してその例外を処理し、場合によっては何らかの例外通知システム (Airbrake など) に例外を渡すために使用しようとしました。の場合after_save、例外はモデルによってスローされ、コントローラーによってキャッチされますが、レコードは保存されません (また、外部システムで例外が発生した場合でも、部分的なデータを保存する必要があります。これは受け入れられません)。 )。の場合after_commit、例外はスローされず、コントローラーによって取得されませんが、部分的なレコードは永続化されます。これは、ユーザーに例外を通知できないことを意味します (何らかの通知プッシュ メカニズムを実装しない限り、これはやり過ぎです)。

結局のところ、 のモデルにエラーを設定できafter_saveます。これは素晴らしいことです。しかし、これはこの種のシナリオを処理するための良い一般的なパターンですか?

4

1 に答える 1

1

そこには多くのオプションがありません。あなたが求めていることのロジック自体は複雑なので、コードを移動してレコードを別の場所 (おそらくサービスを表すクラスメソッドまたは別のクラス) に保存し、誰かがこの特定のオブジェクトを保存したい場合は、このサービス モデルを実行します。

例えば:

class MyModelPersistenceService

    def save_model( model )
      result = model.save
      if result
        call_external_service
      end
    end 

end

サービスは Ruby/Rails プロジェクトではあまり一般的ではありませんが、この種の使用法には適しています (AR コールバックを悪用すると、通常、オブジェクトのテストが難しくなります)。

于 2012-06-07T21:38:55.910 に答える