This project is archived and is in readonly mode.
HABTM association is being destroyed before the before_destory callbacks are executed
Reported by Golly | December 19th, 2010 @ 08:17 AM
Here is some example code.
Two models with a unique HABTM ass. on each other. One model has a
before_destroy callback.
class AudioTag < ActiveRecord::Base
has_and_belongs_to_many :tracks, :uniq => true
before_destroy do |r|
logger.info "[AudioTag] Before destroy"
end
end
class Track < ActiveRecord::Base
has_and_belongs_to_many :audio_tags, :uniq => true
end
Now the problem: from a unit test I run this:
audio_tag.destroy
As you can see from the following logging, the association is
destroyed before the callbacks are called.
SQL (0.2ms) SELECT COUNT(*) FROM `audio_tags`
SQL (0.1ms) SELECT COUNT(*) FROM `tracks`
SQL (0.1ms) select count(*) from audio_tags_tracks
AudioTag Load (0.4ms) SELECT `audio_tags`.* FROM `audio_tags` WHERE (`audio_tags`.`id` = 235380211) LIMIT 1
Track Load (0.4ms) SELECT * FROM `tracks` INNER JOIN `audio_tags_tracks` ON `tracks`.id = `audio_tags_tracks`.track_id WHERE (`audio_tags_tracks`.audio_tag_id = 235380211 )
SQL (0.1ms) SAVEPOINT active_record_1
AREL (0.2ms) DELETE FROM `audio_tags_tracks` WHERE `audio_tags_tracks`.`audio_tag_id` = 235380211 AND `audio_tags_tracks`.`track_id` IN (761148351)
SQL (0.1ms) RELEASE SAVEPOINT active_record_1
SQL (0.1ms) SAVEPOINT active_record_1
[AudioTag] Before destroy
AREL (0.2ms) DELETE FROM `audio_tags` WHERE (`audio_tags`.`id` = 235380211)
SQL (0.1ms) RELEASE SAVEPOINT active_record_1
SQL (0.2ms) SELECT COUNT(*) FROM `audio_tags`
SQL (0.1ms) SELECT COUNT(*) FROM `tracks`
SQL (18.4ms) ROLLBACK
So to be extra clear, the two lines that matter here
are:
AREL (0.2ms) DELETE FROM
audio_tags_tracks WHEREaudio_tags_tracks
.audio_tag_id
= 235380211 ANDaudio_tags_tracks
.track_id
IN (761148351)
[AudioTag] Before destroy
The before_destroy callbacks should be called before any modifications are made to the model.
Most likely related to #4386.
Comments and changes to this ticket
-
Ed4 February 4th, 2011 @ 05:52 PM
This looks to me like a serious issue, because it's no longer possible to use a before_destroy callback to check for the existence of associated HABTM records. In the following example, the callback never sees any associated lessons:
class Student < ActiveRecord::Base has_and_belongs_to_many :lessons before_destroy {|s| s.lessons.empty? } end
This worked in Rails 2.x, and broke when I tried to upgrade to Rails 3.
I tried defining the callback before the association to tweak their order, but it doesn't solve the problem.
-
Ed4 February 4th, 2011 @ 09:09 PM
Here is a patch to fix this, including a new unit test. There was an existing unit test that actually tests for the wrong behavior (it forces the deletion of association records before entering the before_destroy callback), so I updated it as well.
-
Repository February 4th, 2011 @ 09:40 PM
- State changed from new to resolved
(from [909588d964bf27f20142a0b4d57890114a8d4a7a]) Fixing ordering of HABTM association deletion [#6191 state:resolved]
Signed-off-by: Santiago Pastorino santiago@wyeworks.com
https://github.com/rails/rails/commit/909588d964bf27f20142a0b4d5789...
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
Attachments
Referenced by
- 4386 dependent => :destroy deletes children before "before_destroy" is executed Probably related to #6191
- 6191 HABTM association is being destroyed before the before_destory callbacks are executed (from [909588d964bf27f20142a0b4d57890114a8d4a7a]) Fixing ...
- 4386 dependent => :destroy deletes children before "before_destroy" is executed Can someone check if this is still an issue after we push...
- 6562 HABTM join tables cleared on destroy even if a before_destroy says don't This is mildly related to #6191 which fixed it so that th...
- 6629 HABTM destroy deletes record before associated records #6191 reordered how destroy works with habtm associations...