Rails - Comments w acts_as_nested_set - When Deleting a Dependent Record is Deleting Destroy Data

1.5k Views Asked by At

I have the following Models:

class Group < ActiveRecord::Base
    has_many :threads, :dependent => :destroy

class Thread < ActiveRecord::Base
    has_many :comments, :as => :commentable, :dependent => :destroy

 class Comment < ActiveRecord::Base
    belongs_to :commentable, :polymorphic => true
    acts_as_nested_set

The issue I'm having is when a user deletes a group, all kinds of comments are being broken or deleted. I took a look at the logs and this is what's happening:

Comment Load (0.8ms)  SELECT "comments".* FROM "comments" WHERE ("comments".commentable_id = 101 AND "comments".commentable_type = 'Thread') ORDER BY comments.created_at DESC
AREL (0.9ms)  DELETE FROM "comments" WHERE ("comments"."lft" > 649 AND "comments"."rgt" < 650)
AREL (0.4ms)  UPDATE "comments" SET "lft" = ("lft" - 2) WHERE ("lft" > 650)
AREL (0.5ms)  UPDATE "comments" SET "rgt" = ("rgt" - 2) WHERE ("rgt" > 650)
AREL (0.2ms)  DELETE FROM "comments" WHERE ("comments"."id" = 381)
AREL (0.4ms)  DELETE FROM "comments" WHERE ("comments"."lft" > 645 AND "comments"."rgt" < 646)
AREL (0.4ms)  UPDATE "comments" SET "lft" = ("lft" - 2) WHERE ("lft" > 646)
AREL (0.4ms)  UPDATE "comments" SET "rgt" = ("rgt" - 2) WHERE ("rgt" > 646)
AREL (0.2ms)  DELETE FROM "comments" WHERE ("comments"."id" = 380)
AREL (0.3ms)  DELETE FROM "comments" WHERE ("comments"."lft" > 648 AND "comments"."rgt" < 651)
AREL (0.3ms)  UPDATE "comments" SET "lft" = ("lft" - 4) WHERE ("lft" > 651)
AREL (0.3ms)  UPDATE "comments" SET "rgt" = ("rgt" - 4) WHERE ("rgt" > 651)
AREL (0.2ms)  DELETE FROM "comments" WHERE ("comments"."id" = 379)
AREL (0.3ms)  DELETE FROM "comments" WHERE ("comments"."lft" > 644 AND "comments"."rgt" < 647)
AREL (0.4ms)  UPDATE "comments" SET "lft" = ("lft" - 4) WHERE ("lft" > 647)
AREL (0.4ms)  UPDATE "comments" SET "rgt" = ("rgt" - 4) WHERE ("rgt" > 647)
AREL (0.2ms)  DELETE FROM "comments" WHERE ("comments"."id" = 378)
AREL (0.4ms)  DELETE FROM "comments" WHERE ("comments"."lft" > 642 AND "comments"."rgt" < 643)
AREL (0.8ms)  UPDATE "comments" SET "lft" = ("lft" - 2) WHERE ("lft" > 643)
AREL (0.4ms)  UPDATE "comments" SET "rgt" = ("rgt" - 2) WHERE ("rgt" > 643)
AREL (0.2ms)  DELETE FROM "comments" WHERE ("comments"."id" = 377)
AREL (0.7ms)  DELETE FROM "comments" WHERE ("comments"."lft" > 641 AND "comments"."rgt" < 652)
AREL (0.9ms)  UPDATE "comments" SET "lft" = ("lft" - 12) WHERE ("lft" > 652)
AREL (0.9ms)  UPDATE "comments" SET "rgt" = ("rgt" - 12) WHERE ("rgt" > 652)
AREL (0.3ms)  DELETE FROM "comments" WHERE ("comments"."id" = 376)
AREL (0.4ms)  DELETE FROM "threads" WHERE ("threads"."id" = 101)
AREL (0.4ms)  DELETE FROM "groups" WHERE ("groups"."id" = 57)

Is this normal behavior for acts as nested? I would have expect just the DELETE FROM COMMENTS where Comment.id = XXXX. But instead all this is going on and comment records are breaking.

Has anyone seen this before?

Thank you

UPDATE w What is being used to prevent deep nesting:

  after_save :ensure_max_nestedset_level
  def ensure_max_nestedset_level
    if self.level > 2
      self.move_to_child_of(parent.parent)
    end
  end
4

There are 4 best solutions below

0
On

Well it's apparently trying to maintain the hierarchy when deleting nodes, a common problem in SQL.

Which library are you using? Awesome Nested Set? Why it would result in broken records I'm not sure.

You can read more about the nested set approach here:

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

See the "Nested Set Model" section, and the "Deleted Nodes" sub-section below for why deletions are managed the way they are.

So the delete statements would be normal behavior.

11
On

This should not be breaking records. When you delete a node, the tree has to be pruned. The comments in acts_as_nested_set say that

"both adding and removing an entry require a full table write."

The code in this before destroy method in acts_as_nested_set is attempting reorganize the table when you delete the Comment records, and is normal behavior.

0
On

It seems unlikely, but never impossible, that the gem you use is unable to delete items and keep the nestedness correct. So imho it is related to something you are doing. It might also be related to the polymorphic relation.

Did you test with the ensure_max_nestedset_level removed? Does it work then? Does it work when you delete a single comment? Delete a parent-comment? (with nested elements under it). Does it only fail when you delete a group/thread?

0
On

Simple acts_as_nested_set creates a tree for all records in the comments table. I guess you should create one comment tree per thread. E.g. acts_as_nested_set :parent_column => :parent_id, :scope => [:commentable_id, :commentable_type].

Notice also that by default associations created by acts_as_nested_set have :dependent set to :delete_all. So make sure that :parent_id is set correctly.

With above modifications when deleting a group, only comments which belong to the group (via threads) should be deleted.

BTW I use awesome_nested_set recommended at ruby-toolbox.