【问题标题】:Rails destroy callbacks for child records not firing on parent updateRails 销毁未在父更新时触发的子记录的回调
【发布时间】:2016-10-01 05:34:25
【问题描述】:

我看到一个问题,即删除父模型的子记录时不会触发子记录上的销毁回调。从表单更新记录时会出现此问题,但我认为这无关紧要。

class Job
  has_many :assignments, dependent: :destroy
  has_many :scheduled_assignments, -> { scheduled }, class_name: 'Assignment'

  accepts_nested_attributes_for :scheduled_assignments, dependent_destroy: true
end


class Assignment
  belongs_to :job

  after_destroy :call_me
  after_save :call_me

  def call_me
    puts "I got called"
  end
end

job = Job.create
job.update({ scheduled_assignment_ids: [1] })
  # a scheduled assignment is created, and the after_save 
  # callback is called in assignment

job.update({ scheduled_assignment_ids: [] })
   # the scheduled assignment is deleted, 
   # but the after_destroy callback is not fired

因为 Rails 文档提到应该使用“销毁”操作而不是“删除”来删除子记录,所以我希望在被删除的 Assignment 对象上触发回调。

【问题讨论】:

  • 更新可以触发这样的销毁吗?要么你应该打电话给job.destroy(),要么我错过了一些关于 ActiveRecord 是如何工作的。
  • 我认为它应该,尤其是当更新触发保存/创建回调时。似乎提交操作应该触发所有回调或都不触发。

标签: ruby-on-rails ruby ruby-on-rails-4


【解决方案1】:

after_destroy不在update触发的回调列表中: http://guides.rubyonrails.org/active_record_callbacks.html(第 3.2 节)

文档使它看起来像这样可以工作:

after_destroy :call_me, on: [ :update ]

【讨论】:

  • after_destroy :call_me, on: [ :update ] 不起作用,子记录中根本没有任何回调被触发。
【解决方案2】:

我通过使用after_remove 解决了这个问题。搜索后Rails source regarding collection associations

def remove_records(existing_records, records, method)
  records.each { |record| callback(:before_remove, record) }

  delete_records(existing_records, method) if existing_records.any?
  records.each { |record| target.delete(record) }

  records.each { |record| callback(:after_remove, record) }
end

您可以看到,无论deletedestroy 是什么,只要删除子记录,就会调用before_removeafter_remove 回调。

因此,当向我的父类添加after_remove 回调时,我可以在每个删除的子记录上手动触发一个方法。这就是我所追求的。

class Job
  has_many :assignments, dependent: :destroy
  has_many :scheduled_assignments, -> { scheduled }, 
                                    class_name: 'Assignment', 
                                    after_remove: :teardown_assignment

  accepts_nested_attributes_for :scheduled_assignments, dependent_destroy: true

  def teardown_assignment(assignment)
    # callback here
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    相关资源
    最近更新 更多