为什么在这个has_many协会中没有“before_remove”解雇?

我想在从has_many关联中删除对象之前运行一些代码。

我认为我可以使用before_remove回调来做到这一点,但由于某种原因,这不是解雇,我不明白为什么。

 class Person < ActiveRecord::Base has_many :limbs, before_remove: :print_message def print_message puts 'removing a limb' end end class Limb < ActiveRecord::Base belongs_to :person end 

虽然这个代码应该在肢体破坏期间打印“移除肢体” ,但事实并非如此。

 p = Person.create; l = Limb.create person: p; p.limbs.first.destroy # SQL (2.1ms) DELETE FROM "limbs" WHERE "limbs"."id" = ? [["id", 5]] # => # 

为什么这会destroy操作不会导致print_message方法运行?

编辑 – 这before_remove存在before_remove回调?

许多人都在询问是否存在此回调。 虽然我可以找到很少的进一步引用,但它在Rails文档中有记录:

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Association+callbacks

它是一个关联回调,而不是根ActiveRecord回调

编辑2 – 为什么不在before_destroy上使用before_destroy

有些人问为什么我没有在Limb上使用before_destroy回调。 原因是我希望人检查是否有最小数量的肢体,并且最后一个肢体永远不会被摧毁。 这是最初的问题: 你如何确保has_many始终“有最小值”?

before_remove回调作为Associations回调中的选项存在。 它与before_destroy ,后者是一个ActiveRecord回调 。

这是你如何使用它:

 class Person < ActiveRecord::Base has_many :limbs, :before_remove => :print_message def print_message(limb) # limb variable references to a Limb instance you're removing # ( do some action here ) # ... end end class Limb < ActiveRecord::Base belongs_to :person end 

您还错误地调用了remove方法。

 p = Person.create l = Limb.create(:person => p) p.limbs.first.destroy 

在这里你在Limb实例上调用它,这就是为什么没有触发的原因。 在您创建的关联上调用它:

 p = Person.create l = Limb.create(:person => p) p.limbs.destroy(l) 

编辑

为了保留最少的关联对象,您可以执行以下操作:

 class Person < ActiveRecord::Base has_many :limbs, :before_remove => :preserve_mimimum def preserve_minimum(limb) raise "Minimum must be preserved" if limbs.count == 1 end end class Limb < ActiveRecord::Base belongs_to :person end 

然而,这不会在p.limbs.destroy_all触发,所以你必须做这样的事情p.limbs.each {|l| p.limbs.destroy(l)} p.limbs.each {|l| p.limbs.destroy(l)}

为什么它不会被destroy_all触发?

因为这:

 def destroy_all(conditions = nil) find(:all, :conditions => conditions).each { |object| object.destroy } end 

它迭代关联的每个元素并对对象执行销毁操作而不是关联,这就是原因。

before_destroy替换before_remove

编辑 – 处理最小数量的肢体

 class Limb < ActiveRecord::Base belongs_to :creature before_destroy :count_limbs def count_limbs return false if self.creature.limbs.length <= self.creature.min_limbs end end 

我认为,这种回归将会阻止它被摧毁。 虽然我错了

我不能说我以前曾经使用过before_remove回调,并且不确定它是否存在。

之前的destroy回调应该是在Limb模型上,而应该是这样的:

 class Limb < ActiveRecord::Base belongs_to :person before_destroy :print_message def print_message puts 'removing a limb' end end