【问题标题】:Is there a Rails 4 circular dependent: :destroy workaround?是否有 Rails 4 循环依赖: :destroy 解决方法?
【发布时间】:2014-04-22 01:00:07
【问题描述】:

以循环dependent: :destroy 问题为例:

class User < ActiveRecord::Base
  has_one: :staff, dependent: :destroy
end

class Staff < ActiveRecord::Base
  belongs_to :user, dependent: :destroy
end

如果我调用user.destroy,关联的staff 也应该被销毁。相反,调用staff.destroy 也应该销毁关联的user

这在 Rails 3.x 中效果很好,但是在 Rails 4.0 中行为发生了变化(并在 4.1 中继续),因此形成了一个循环,最终你会得到一个错误,“堆栈级别太深”。一种明显的解决方法是使用before_destroyafter_destroy 创建自定义回调来手动销毁关联的对象,而不是使用dependent: :destroy 机制。即使是 issue in GitHub opened for this 情况也有几个人推荐这种解决方法。

不幸的是,我什至无法让这种解决方法发挥作用。这就是我所拥有的:

class User < ActiveRecord::Base
  has_one: :staff

  after_destroy :destroy_staff

  def destroy_staff
    staff.destroy if staff and !staff.destroyed?
  end
end

这不起作用的原因是staff.destroyed? 总是返回false。这样就形成了一个循环。

【问题讨论】:

  • 您是否按照 Jken13579 的建议在两个模型中实现了该逻辑?
  • @xlembouras,没有尝试过,但我很确定它不会起作用。为了确定,我会在这周的某个时候尝试一下。我在下面写了为什么它不起作用。
  • @at。我的回答好运吗?

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-4 ruby-on-rails-4.1


【解决方案1】:

如果循环的一侧只有一个回调,您可以将其中一个 dependent: :destroy 替换为 dependent: :delete

class User < ActiveRecord::Base
  # delete prevents Staff's :destroy callback from happening
  has_one: :staff, dependent: :delete
  has_many :other_things, dependent: :destroy
end

class Staff < ActiveRecord::Base
  # use :destroy here so that other_things are properly removed
  belongs_to :user, dependent: :destroy
end

对我来说效果很好,只要一侧不需要其他回调即可触发。

【讨论】:

    【解决方案2】:

    我也遇到了这个问题,并提出了一个不漂亮但有效的解决方案。本质上,您只需使用类似于destroy_staffdestroy_user

    class User < ActiveRecord::Base
      has_one: :staff
    
      after_destroy :destroy_staff
    
      def destroy_staff
        staff.destroy if staff && !staff.destroyed?
      end
    end
    
    class Staff < ActiveRecord::Base
      belongs_to :user
    
      after_destroy :destroy_user
    
      def destroy_user
        user.destroy if user && !user.destroyed?
      end
    end
    

    【讨论】:

    • 奇怪,stackoverflow 没有更新我的收件箱,告诉你你有答案。我会试试这个,但我敢肯定它不会工作。我尝试了很多变化。如果从 before_destroyafter_destroy 回调中调用,基本上任何 .destroyed? 调用 always 在 Rails 4.1 中都会返回 false。
    • 希望它在 Rails 4.1 中对你有用,因为我只在 Rails 4.0 中测试过它,尽管我想这应该没什么区别。
    猜你喜欢
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 2017-04-27
    • 2014-12-26
    • 2020-11-12
    相关资源
    最近更新 更多