4

別のオブジェクトが破棄された後、親オブジェクトの依存関係を更新したいという状況があります。クラス階層の例を次に示します。

class Parent < ActiveRecord::Base
  has_one  :info, :dependent => :destroy
  has_many :conditions, :dependent => :destroy
  ....
end

class Info < ActiveRecord::Base
  belongs_to :parent

  def recalculate
    # Do stuff
  end
  ....
end

class Condition < ActiveRecord::Base
  belongs_to :parent
  has_one :condition_detail

  after_destroy :update_info

  def update_info
    parent.info.recalculate
    parent.info.save(:validate => false)
  end
  ....
end

問題は、親が破棄されると、条件が破棄され、その後、after_destroyコールバックが開始され、既に破棄された後に情報オブジェクトが保存されることです。したがって、親が破棄された後も情報は存在します。検証をバイパスしないと、保存はサイレントに失敗しますが、これは望ましくありません。そして保存を使用して!例外を発生させます。

Conditionのコールバックはafter_destroyである必要があります。そうしないと、Infoのrecalculateメソッドは、必要なものを計算するための関係の状態を正しく表現できません。

親が破壊されたときにコールバックをバイパスする方法が必要なように感じますが、それは不可能だと思います。依存=>delete_allを使用することはできません。これは、Conditionの子を破棄しないためです。親がdestroyを呼び出したかどうかを判断し、その情報を使用してafter_destroyの保存をバイパスする方法があるかどうかを確認しようとしましたが、それも機能しなかったようです。

どんな助けでも大歓迎です、ありがとう!

4

1 に答える 1

7

2つのオプションがあるようです。

  1. Conditionでコールバックを使用しないでくださいafter_destroy。むしろ、Conditionを破棄している人が情報を再計算することを期待してください。オブジェクトの破棄と計算という2つの別個のインテントを分離しているため、これが最もクリーンです。たとえば、いつか2つの条件を一度に破棄し、両方が破棄された後でのみ再計算する場合に、これがより役立つ場所を確認できます。コールバックではこれを行うことはできません。また、デメテルの法則Condition.destroyとより密接に一致します。呼び出しの呼び出し元はinfo.recalculate、条件呼び出しよりも優れていparent.info.recalculateます。

    この動作を本当にConditionにパッケージ化する場合は、一種の非表示のコールバックで#destroy_and_recalculateはなく呼び出される関数を作成します。#destroy再計算を開始することは、発信者にとってより明白です。

  2. :dependent=>destroy親の関連付けを削除し、それを独自のコールバックに:condition置き換えます。これにより、コールバックなしで破棄されます。before_destroyParentcondition

    Conditionでは、たとえば、このメソッドを作成し#destroy_without_callbacks、その中にConditionの子を作成してから、Conditionをそれ自体destroyに引き起こします。delete

の機能:dependent=>destroyは素晴らしいですが、このようなサイクルでは、魔法の一部を取り除き、オブジェクトとプロセスのライフサイクルをより明示的に管理することで、実行していることを非常に明確にすることが最も明確な方法だと思います。

于 2013-01-15T23:13:54.903 に答える