Associations are not consistent in honoring :dependent => destroy (db is fill with orphaned objects)

if a model A has_many :bee, :through => :c, :dependent => :destroy
a.destroy properly cleans up all the bee's ...

If one does this:

a.bees = []
c records are destroyed... bees are untouched.

This is misleading to me, as: while I can understand semantics that
just the "array" has been modified...
something like :dependent => :destroy should be invariant (the
dependents should be destroyed, under all cases where... the object is
a dependent)

I am new to this list, so: how does one file a ticket?


The behaviour of deletion/destruction on associations can be confusing,
and there is a lack of documentation. I have done some work recently to
improve consistency across the different types of associations, and
improve the documentation too.

So the current situation in master is that:

* delete/destroy on an association removes the "link", and not
necessarily the actual associated records. For has_many the "link" is
the records itself, so there is no distinction. For has_many :through
and has_and_belongs_to_many, only the join/through record is removed as
this is the "link".

* Doing a.association.delete(*records) will perform the deletion
according to the :dependent option. Using the :dependent option
basically causes a before_destroy callback to call

With has_many :through, if you want to remove the associated records
also, then you should probably add the :dependent option to the source
association in your join model.

Jon is where to file a ticket.

However, I don't think this is a bug - :dependent => :destroy only specifies what happens when the object that declares the association gets destroyed - in your second case, you're not destroying 'a'.

If you *really* want this behavior, you can probably get it with :dependent => :destroy on the association in model 'C', but the resulting behavior will make *lots* of records vanish that you might not have intended. For instance, here's a simple set of associations:

class Project < AR::Base
  has_many :task_assignments, :dependent => :destroy # 1
  has_many :users, :through => :task_assignments

class TaskAssignment < AR::Base
  belongs_to :project, :dependent => :destroy #3
  belongs_to :user

class User < AR::Base
  has_many :task_assignments, :dependent => :destroy # 2
  has_many :projects, :through => :task_assignments

the lines labelled #1 and #2 above are typically a good idea, as they ensure that join records referencing an object are cleaned up when the object is destroyed. #3, on the other hand, means that deleting a user will delete every Project that user was assigned to, as will doing 'user.projects = []'...

--Matt Jones

Please note that the documentation clearly says the :dependent option
is ignored altogether for hmt. It is better to work on the join model.