我想在从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
Run Code Online (Sandbox Code Playgroud)
虽然这个代码应该在肢体破坏期间打印"去除肢体",但事实并非如此.
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">
Run Code Online (Sandbox Code Playgroud)
为什么此destroy操作不会导致该print_message方法运行?
编辑 - 这before_remove回调存在吗?
很多人都问过这个回调是否存在.虽然我可以找到很少的进一步引用,但它在Rails文档中有记录:
它是一个关联回调,而不是根ActiveRecord回调
编辑2 - 为什么不在before_destroyLimb上使用?
有些人在问我为什么不在before_destroyLimb上使用回调.原因是我希望人检查是否有最小数量的肢体,并且最后一个肢体永远不会被摧毁.这是最初的问题:
你如何确保has_many始终"有最小值"?
shi*_*ime 18
before_remove回调作为" 关联"回调中的选项存在.这是不一样的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
Run Code Online (Sandbox Code Playgroud)
你也remove错误地调用了一个方法.
p = Person.create
l = Limb.create(:person => p)
p.limbs.first.destroy
Run Code Online (Sandbox Code Playgroud)
在这里你是在Limb实例上调用它,这就是为什么没有触发的原因.在您创建的关联上调用它:
p = Person.create
l = Limb.create(:person => p)
p.limbs.destroy(l)
Run Code Online (Sandbox Code Playgroud)
编辑
为了保留最少的关联对象,您可以执行以下操作:
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
Run Code Online (Sandbox Code Playgroud)
然而,这不会被触发p.limbs.destroy_all,所以你必须做这样的事情p.limbs.each {|l| p.limbs.destroy(l)}
为什么它不被触发destroy_all?
因为这:
def destroy_all(conditions = nil)
find(:all, :conditions => conditions).each { |object| object.destroy }
end
Run Code Online (Sandbox Code Playgroud)
它迭代关联的每个元素并对对象执行销毁操作而不是关联,这就是原因.