gpt4 book ai didi

ruby-on-rails - rails/ ruby : Self-referential association using dependent: :destroy causing duplicate callbacks

转载 作者:太空宇宙 更新时间:2023-11-03 16:49:41 24 4
gpt4 key购买 nike

很难在标题中正确表达我的问题,但我会尝试更详细地简要解释一下。

我需要在我的一个模型中使用自引用关联,如下所示:

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如果存在,则首先为 child ,然后调用 destroy对于原来的 parent 。然而,这是一个问题,在上面 destroy_standing_events例如,因为即使在 destroy 之后已通过 dependent: :destroy 对子记录调用方法子句,它将使 destroy第二次调用,触发我的 after_destroy :do_stuff第二次回调。

尝试的解决方案

到目前为止,我已经尝试了以下(没有成功):
  • 已更改 after_destroybefore_destroy以防回调顺序很时髦
  • 试过检查standing_event.destroyed?外部状态destroy_standing_events方法和内部:do_stuff回调方法
  • 尝试使用附加到 StandingEvent 的自定义标志模型来指示 :do_stuff 的 Action 是否已经应用或不应用“破解”一种防止重复的方法。

  • 不幸的是,到目前为止,我发现的唯一“解决方案”本质上是在外部运行辅助数据库查找 destroy_standing_events在完成 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

    因此,虽然上述解决方案在技术上有效,但我不禁觉得那里有更好的解决方案,尤其是不需要这么多额外数据库查询的解决方案。

    任何指导或帮助将不胜感激!

    解决方案

    感谢@pdobb 下面的建议,通过限制返回的 StandingEvents 的集合,我能够仅使用一个数据库查询来解决我的特定问题。仅用于那些没有任何父/子关联记录的记录, 作为 parent 的记录。

    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

    以上是 StandingEvent的相关代码模型,我在其中添加了四个类方法来查询特定的集合。然后我捕获 no_parent 的合并和 no_children集合,代表所有没有关联的记录,可以自由销毁。然后,由于 has_many :children, dependent: :destroy StandingEvent 中的子句,我还需要包含那些具有 children 的记录使用 has_children方法。

    为了简化调用,将以上所有内容组合成 dominant方法,我在这里使用 ActiverecordAnyOf gem只是简单地创建一个简单的“OR”数据库查询(尽管没有 AnyOf gem 的相同结果可以使用自定义 SQL 或 AREL 来完成。)

    正如@pdobb 所建议的,最终结果是我可以调用 dominant记录为 destroyed在我的外线电话中:

    def destroy_standing_events
    self.standing_events.dominant.destroy_all
    end

    最佳答案

    一开始只尝试删除 parent (不包括 child )怎么样?

    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

    那么你的循环将不包括开始的 child 和 dependent: :destroy选项将负责销毁相关的 child 。注意:范围语法假定 Rails 4.x。

    关于ruby-on-rails - rails/ ruby : Self-referential association using dependent: :destroy causing duplicate callbacks,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25231774/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com