Is there a Rails 4 circular dependent: :destroy workaround?

谁说胖子不能爱 提交于 2019-12-21 03:43:15

问题


As an example for the circular dependent: :destroy issue:

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

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

If I call user.destroy, the associated staff should be destroyed as well. Conversely, calling staff.destroy should destroy the associated user as well.

This worked great in Rails 3.x, but the behavior changed in Rails 4.0 (and continues in 4.1) such that a loop forms and eventually you get an error, "stack level too deep." One obvious workaround is to create a custom callback using before_destroy or after_destroy to manually destroy the associated objects instead of using the dependent: :destroy mechanism. Even the issue in GitHub opened for this situation had a couple people recommending this workaround.

Unfortunately, I can't even get that workaround to work. This is what I have:

class User < ActiveRecord::Base
  has_one: :staff

  after_destroy :destroy_staff

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

The reason this doesn't work is that staff.destroyed? always returns false. So it forms a cycle.


回答1:


If one side of the cycle only has that one callback, you can replace one of the dependent: :destroy with 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

Worked great for me, as long as one side doesn't need other callbacks to fire.




回答2:


I faced this issue as well, and came up with a solution that isn't pretty but works. Essentially, you'd just use a destroy_user that's similar to 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


来源:https://stackoverflow.com/questions/23208579/is-there-a-rails-4-circular-dependent-destroy-workaround

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!