Surprise in (delete_all | clear | destroy_all) on association

Hi,
I was very surprised by difference of delete_all on association vs model(delegated to relation).
Given TaskFilter.has_many(:qualifiers, :class_name=>‘TaskFilterQualifier’)

TaskFilter.delete_all => one DELETE statement

Without :dependent option on “qualifiers” association
TaskFilter.first.qualifiers.delete_all =>
SELECT task_filter_qualifiers.* FROM task_filter_qualifiers WHERE (task_filter_qualifiers.task_filter_id = 1)
BEGIN
UPDATE task_filter_qualifiers SET task_filter_id = NULL WHERE task_filter_qualifiers.task_filter_id = 1 AND task_filter_qualifiers.id IN (90, 91)
COMMIT

Why UPDATE, not DELETE ?

With :dependent => :destroy
TaskFilter.first.qualifiers.delete_all =>

TaskFilter Load (0.9ms) SELECT task_filters.* FROM task_filters LIMIT 1
TaskFilterQualifier Load (0.9ms) SELECT task_filter_qualifiers.* FROM task_filter_qualifiers WHERE (task_filter_qualifiers.task_filter_id = 1)
SQL (0.2ms) BEGIN
AREL (6.6ms) DELETE FROM task_filter_qualifiers WHERE (task_filter_qualifiers.id = 92)
TaskFilter Load (6.4ms) SELECT task_filters.* FROM task_filters WHERE (task_filters.id = 1) LIMIT 1
AREL (0.6ms) UPDATE task_filters SET updated_at = ‘2010-11-24 09:28:03’ WHERE (task_filters.id = 1)
AREL (2.6ms) DELETE FROM task_filter_qualifiers WHERE (task_filter_qualifiers.id = 93)
TaskFilter Load (8.2ms) SELECT task_filters.* FROM task_filters WHERE (task_filters.id = 1) LIMIT 1
AREL (1.7ms) UPDATE task_filters SET updated_at = ‘2010-11-24 09:28:03’ WHERE (task_filters.id = 1)
SQL (53.5ms) COMMIT

Note that I have :touch option, so sql below is produced by :touch callback
TaskFilter Load (6.4ms) SELECT task_filters.* FROM task_filters WHERE (task_filters.id = 1) LIMIT 1

AREL (0.6ms) UPDATE task_filters SET updated_at = ‘2010-11-24 09:28:03’ WHERE (task_filters.id = 1)

That is nightmare, I expect delete_all to be fast sql query, but instead I have:

  • all associated objects loaded
  • each object was destroyed, with many callbacks and DELETE queries

delete_all, clear, destroy_all respect :dependent option, but why ?
If association hasn’t :dependent option, then delete_all is duplicate of clear
if association has :dependent=> :destroy option, then delete_all, clear are duplicates of destroy_all

delete_all work fine on relation so, TaskFilter.first.qualifiers.scoped.delete_all will work fine:
TaskFilter Load (1.3ms) SELECT task_filters.* FROM task_filters LIMIT 1
AREL (71.7ms) DELETE FROM task_filter_qualifiers WHERE (task_filter_qualifiers.task_filter_id = 1)

Is this all intentional behavior ?

Maybe this ticket is related https://rails.lighthouseapp.com/projects/8994/tickets/5196-delete_allnullify-in-associations-does-uneeded-queries

Thanks,
Anatoliy Lysenko