很难在标题中正确地说出我的问题,但我会尝试更详细地解释一下。
我需要在我的一个模型中使用自引用关联,如下所示:
class StandingEvent < Event
has_many :children, class_name: "StandingEvent", foreign_key: "parent_id", dependent: :destroy
belongs_to :parent, class_name: "StandingEvent"
after_destroy :do_stuff
...
end
问题是,当我在一系列StandingEvent.destroy
记录上调用StandingEvent
方法时 - 例如来自其他相关模型的记录 - 任何StandingEvent
记录已分配的parent_id
总是运行after_destroy
回调方法两次 。
当我想销毁集合中的所有StandingEvent
条记录时,这是一个问题,例如代码中其他地方调用的此方法:
def destroy_standing_events
self.standing_events.each do |standing_event|
standing_event.destroy
end
end
我当然已经收集到,这是dependent: :destroy
has_many :children
关联使用destroy
的预期行为,因为如果存在,则显然会先为孩子调用destroy
然后为原始父母调用destroy_standing_events
。但是,在上面的destroy
示例中,这是一个问题,因为即使在通过dependent: :destroy
子句在子记录上调用destroy
方法之后,它也会生成after_destroy :do_stuff
}再次呼叫,第二次触发我的after_destroy
回叫。
尝试解决方案
到目前为止,我已尝试过以下方法(未成功):
before_destroy
更改为standing_event.destroyed?
,以防万一回调订单质朴。destroy_standing_events
方法和内部:do_stuff
回调方法中检查StandingEvent
状态:do_stuff
模型的自定义标记来指示destroy_standing_events
的操作是否已经应用于&#34; hack&#34;一种防止重复的方法。不幸的是,到目前为止唯一的&#34;解决方案&#34;我发现基本上是在外部destroy
方法中运行辅助数据库查找,以确保在完成def destroy_standing_events
self.standing_events.each do |standing_event|
# Verify that each event exists
standing_event = StandingEvent.find_by(id: standing_event.id)
standing_event.destroy unless standing_event.nil?
end
end
调用之前记录尚未被销毁,如下所示:< / p>
StandingEvents
所以,虽然上述解决方案在技术上有效,但我无法帮助但感觉那里有更好的解决方案,特别是那些不需要这么多额外数据库查询的解决方案。
非常感谢任何指导或帮助!
感谢@ pdobb的建议,我通过将返回的StandingEvent < Event
has_many :children, class_name: "StandingEvent", foreign_key: "parent_id", dependent: :destroy
belongs_to :parent, class_name: "StandingEvent"
def self.dominant
where.any_of(no_parent.merge(no_children), has_children)
end
def self.has_children
includes(:children).where.not(children_events: { id: nil })
end
def self.no_children
includes(:children).where(children_events: { id: nil })
end
def self.no_parent
where(parent: nil)
end
的集合仅限于仅限于那些记录而仅使用一个数据库查询来找出我的特定问题的解决方案任何父/子关联记录, OR 父母的记录。
StandingEvent
上面是no_parent
模型的相关代码,我在其中添加了四个类方法来查询特定的集合。然后我抓住no_children
和has_many :children, dependent: :destroy
集合的合并,它代表所有没有可以自由销毁的关联的记录。然后,由于StandingEvent
中的children
子句,我还需要使用has_children
方法包含那些dominant
的记录。
为了简化通话,以上所有内容都合并到dominant
方法中,我只使用ActiverecordAnyOf gem创建一个简单的&#34; OR&#34;数据库查询(虽然没有 AnyOf gem的相同结果可以通过自定义SQL或AREL完成。)
根据@pdobb的建议,最终结果是我可以在外线通话中将destroyed
记录称为def destroy_standing_events
self.standing_events.dominant.destroy_all
end
:
{{1}}
答案 0 :(得分:0)
如果只是首先尝试删除父母(不包括孩子)?
def destroy_standing_events
standing_events.is_parent.destroy_all
end
其中is_child
是在 StandingEvent 上定义的范围:
class StandingEvent < ActiveRecord::Base
scope :is_parent, -> { where.not(parent_id: nil) }
end
然后你的循环不包括开始的孩子,dependent: :destroy
选项会照顾破坏相关的孩子。注意:范围语法假定为Rails 4.x。
答案 1 :(得分:0)
假设它是一个无循环图,您可以执行以下操作 摆脱依赖的破坏
def self.dest_rec node
node.children.each{ |c| dest_rec c }
node.destroy
end
如果图表不是自由循环适应
def self.dest_rec node, already_destroyed={}
node.children.each do | c |
next if already_destroyed[c.id]
already_destroyed[c.id] = true # What a liar I am ;)
dest_rec c, already_detroyed
end
node.destroy
end
这是一个n db查找树高(或最长的非循环路径)的一般情况 of。
我们可以做得更好吗?