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