web-dev-qa-db-ja.com

関連付けを通じてhas_manyでコールバックを使用するにはどうすればよいですか?

Has_many throughを介してプロジェクトモデルに関連付けられたタスクモデルがあり、関連付けを介して削除/挿入する前にデータを操作する必要があります。

" 結合モデルの自動削除は直接であるため、破棄コールバックはトリガーされません。 "これにはコールバックを使用できません。

タスクでは、タスクが保存された後、プロジェクトの値を計算するためにすべてのproject_idsが必要です。アソシエーションを介してhas_manyで削除を無効にするか、削除を変更して破棄するにはどうすればよいですか?この問題のベストプラクティスは何ですか?

class Task
  has_many :project_tasks
  has_many :projects, :through => :project_tasks

class ProjectTask
  belongs_to :project
  belongs_to :task

class Project
  has_many :project_tasks
  has_many :tasks, :through => :project_tasks
23
tonymarschall

私は使用しなければならないようです アソシエーションコールバックbefore_addafter_addbefore_removeまたはafter_remove

class Task
  has_many :project_tasks
  has_many :projects, :through => :project_tasks, 
                      :before_remove => :my_before_remove, 
                      :after_remove => :my_after_remove
  protected

  def my_before_remove(obj)
    ...
  end

  def my_after_remove(obj)
    ...
  end
end   
53
tonymarschall

これは私がしたことです

モデル内:

class Body < ActiveRecord::Base
  has_many :hands, dependent: destroy
  has_many :fingers, through: :hands, after_remove: :touch_self
end

私のLibフォルダー内:

module ActiveRecord
  class Base
  private
    def touch_self(obj)
      obj.touch && self.touch
    end
  end
end
1
Nicolai

結合モデルの関連付けを更新すると、Railsコレクションのレコードが追加および削除されます。レコードを削除するには、Rails deleteメソッドとこれを使用します コールバックの破棄 は呼び出されません。

レコードを削除するときに、Railsがdestroyの代わりにdeleteを呼び出すように強制できます。これを行うには、gem replace_with_destroy をインストールして渡しますオプション replace_with_destroy: truehas_manyアソシエーションに。

class Task
  has_many :project_tasks
  has_many :projects, :through => :project_tasks,
            replace_with_destroy: true
  ...
end

class ProjectTask
  belongs_to :project
  belongs_to :task

  # any destroy callback in this model will be executed
  #...

end

class Project
  ...
end

これにより、Railsすべての コールバックの破棄 を呼び出すようになります。これは、 パラノイア を使用している場合に非常に役立ちます。