是否存在Rails 4循环依赖::破坏变通方法?

at.*_*at. 12 ruby-on-rails ruby-on-rails-3 ruby-on-rails-4 ruby-on-rails-4.1

作为循环dependent: :destroy问题的一个例子:

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

class Staff < ActiveRecord::Base
  belongs_to :user, dependent: :destroy
end
Run Code Online (Sandbox Code Playgroud)

如果我打电话user.destroy,也staff应该销毁相关联.相反,调用也staff.destroy应该破坏关联user.

这在Rails 3.x中运行得很好,但是Rails 4.0中的行为发生了变化(并且在4.1中继续),这样就形成了一个循环并最终得到一个错误,"堆栈级别太深了".一个明显的解决方法是使用before_destroyafter_destroy手动销毁关联对象而不是使用该dependent: :destroy机制来创建自定义回调.甚至GitHub中针对这种情况开放的问题也有一些人推荐这种解决方法.

不幸的是,我甚至无法解决这个问题.这就是我所拥有的:

class User < ActiveRecord::Base
  has_one: :staff

  after_destroy :destroy_staff

  def destroy_staff
    staff.destroy if staff and !staff.destroyed?
  end
end
Run Code Online (Sandbox Code Playgroud)

这不起作用的原因是staff.destroyed?始终返回false.所以它形成了一个循环.

Rya*_*arn 5

如果循环的一侧仅具有一个回调,可以代替的一个dependent: :destroydependent: :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
Run Code Online (Sandbox Code Playgroud)

对我来说很有用,只要一方不需要其他回调来解雇.


Joe*_*edy 4

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

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
Run Code Online (Sandbox Code Playgroud)