I have a relationship like so:
Parent
has_many :children
Child
belongs_to :parent
What I want to do is to delete the parent if there are no more children left. So to do this I have:
Child
before_destroy :destroy_orphaned_parent
def destroy_orphaned_parent
parent.children.each do |c|
return if c != self
end
parent.destroy
end
This works fine, however I also want to cascade the delete of the parent to the child. E.g. I would normally do:
Parent
has_many :children, :dependent => :destroy
This causes the WebRick server to crash when I test it. I assume this is due to an infinite loop of the last child deleting the parent deleting the child etc.
I am starting to think that there is a better way to do this? Anyone have any ideas? Is there a way to prevent this recursion?
I accomplished this in the following way:
before_destroy :find_parent
after_destroy :destroy_orphaned_parent
def find_parent
@parent = self.parent
end
def destroy_orphaned_parent
if @parent.children.length == 0
@parent.destroy
end
end
As per Anwar's suggestion, this can also be accomplished using an around
callback, as follows:
around_destroy :destroy_orphaned_parent
def destroy_orphaned_parent
parent = self.parent
yield # executes a DELETE database statement
if parent.children.length == 0
parent.destroy
end
end
I haven't tested the above solution, so feel free to update it, if necessary.
Some Ideas:
You could delete orphaned parents in
an after_destroy
(find them using a
statement like the one on
http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/a3f12d578f5a2619)
You could set some instance variable in before_destroy
containing the parent's ID, then do a lookup based on this id in an after_destroy
callback and decide whether to delete the parent there based on counting the children
Use an after_destroy
callback.
after_destroy :release_parent
def release_parent
if parent.children.count.zero?
parent.destroy
end
end
Using Rails 3.2.15
You can accomplish this using around_destroy
callback
around_destroy :destroy_orphaned_parent
def destroy_orphaned_parent
@parent = self.parent
yield
@parent.destroy if @parent.children.length == 0
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With