ruby-on-rails – 为什么在这个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]]
# => #<Limb id: 5,person_id: 3,created_at: "2012-01-17 11:28:01",updated_at: "2012-01-17 11:28:01">

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

编辑 – 这是否存在before_remove回调?

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

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

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

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

有些人问为什么我没有在Limb上使用before_destroy回调.原因是我希望人检查是否有最小数量的肢体,并且最后一个肢体永远不会被摧毁.这是原始问题:
How do you ensure that has_many always “has a minimum”?

解决方法

before_remove回调作为 Associations callbacks中的选项存在.它与before_destroy不同,后者是 ActiveRecord callback.

这是你如何使用它:

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

您还错误调用删除方法.

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(1)}

为什么它不会被destroy_all触发?

因为这:

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

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

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...