为什么ActiveRecord has_many使用delete_all而不是destroy_all?

时间:2010-01-12 09:34:06

标签: ruby-on-rails activerecord associations has-many

我有一个有很多孩子的模特。我正在设置/删除孩子:

mymodel.children_ids = [1,2,3]
mymodel.save #add the children
mymodel.children_ids = [1]
mymodel.save #remove children 2,3

这很好用,但我刚才意识到没有回调(即after_destroy)没有在子模型上调用。

经过一番挖掘,结果发现delete_all函数正在执行,而不是destroy_all。正如文档正确陈述的那样,delete_all函数不会触发回调,所以无论如何都要改变这种行为?

感谢。

4 个答案:

答案 0 :(得分:1)

delete_all正在执行......只是因为?这就是Rails核心团队在该实例中应该调用的内容。但是,您可以在模型的子项上显式调用destroy_all方法,但不能使用该类型的查询。您似乎直接设置子ID,而不是使用任何build()destroy()方法。

是的,您可以覆盖其功能。您可以对其进行修补并将其放入/vendor,然后使用destroy_all重写相同的代码块。然后使用send命令将基本ActiveRecord功能替换为您自己的功能。

答案 1 :(得分:1)

类似的东西:

mymodel.children.find([2,3]).each {|c| c.destroy }

将完成这项工作。这不完全是你想要的,但我希望它有所帮助。

答案 2 :(得分:1)

对于那些感兴趣的人,我添加了以下monkeypatch来强制has_many执行destroy_all,而不是delete_all。可能有更好的方法,所以我愿意接受建议。

module ActiveRecord 
  module Associations
    class HasManyThroughAssociation < HasManyAssociation       
      def delete_records(records)
        klass = @reflection.through_reflection.klass
        records.each do |associate|
          klass.destroy_all(construct_join_attributes(associate)) #force auditing by using destroy_all rather than delete all
        end
      end
    end
  end
end

答案 3 :(得分:1)

我遇到类似的回调问题。使用alias_method_chain解决了它,以覆盖默认的setter。

  def product_categories_with_destroy=(product_categories)
    unless new_record? 
      (self.product_categories - product_categories).each(&:destroy)
    end

    self.product_categories_without_destroy = product_categories
  end
  alias_method_chain :product_categories=, :destroy

有关alias_method_chain的更多详情:

http://yehudakatz.com/2009/03/06/alias_method_chain-in-models/

相关问题