2

ここに私の before_save メソッドがあります:

  before_save :check_postal

  def check_postal
    first_three = self.postal_code[0..2]
    first_three.downcase!

    postal = Postal.find_by_postal_code(first_three)

    if postal
      self.zone_id = postal.zone_id
    else
      PostalError.create(postal_code: self.postal_code)
      return false
    end
  end

すべてが正常に実行されますが、ステートメントself.zone_id = postal.zone_id内では、レコードがデータベースに保存されません..elsePostalError.create(postal_code: self.postal_code)

ステートメントを削除すると問題なく保存されるため、ステートメントと関係があることはわかっていますreturn falseが、それでは目的が無効になります..

PostalError現在のオブジェクトが保存されないように false を返しながら、保存する新しいレコードを取得するにはどうすればよいですか..

4

2 に答える 2

4

その通りです。問題はbefore_save.

保存プロセス全体がトランザクションにラップされます。保存が失敗した場合、それが検証の失敗、ロールバック中の例外、またはその他の理由であるかどうかにかかわらず、トランザクションはロールバックされます。これにより、PostalError レコードの作成が取り消されます。

通常、これは良いことです - 不完全な保存が残骸を残さないようにするためです

これを解決するには2つの方法が考えられます。1 つは、そこにレコードをまったく作成しないことです。危険が過ぎ去ったら、after_rollbackフックを使用してレコードを実行します。

もう 1 つの方法は、別のデータベース接続を使用してそのレコードを作成することです (トランザクションは接続ごとのものであるため)。これを行う簡単な方法は、別のスレッドを使用することです。

Thread.new { PostalError.create(...)}.join

join予期しない程度の同時実行性をアプリに追加するのではなく、スレッドが完了するのを待つように、そこに貼り付けました。

于 2013-07-07T08:11:48.487 に答える
-2

わかりませんが、解決策を推測しようとしています。

else
  PostalError.create(postal_code: self.postal_code)
  self.zone_id = postal.zone_id
end
于 2013-07-06T22:56:32.033 に答える