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

时间:2014-04-22 01:00:08

标签: 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

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

这在Rails 3.x中运行得很好,但是Rails 4.0中的行为发生了变化(并且在4.1中继续),这样就形成了一个循环,最终你得到一个错误,#34;堆栈级别太深了。&#34;一个明显的解决方法是使用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。所以它形成了一个循环。

2 个答案:

答案 0 :(得分:5)

如果周期的一侧只有一个回调,您可以用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

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

答案 1 :(得分: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