diff options
author | Tomas D'Stefano <tomasdestefi@gmail.com> | 2011-05-31 11:43:19 -0300 |
---|---|---|
committer | Jon Leighton <j@jonathanleighton.com> | 2011-07-08 22:26:54 +0100 |
commit | ea4b94a7bf707d27af44701fa44ef5f916b84e01 (patch) | |
tree | ae5ef07b2cccc9f5dc0d8a1c0f453fe4123dd9ff | |
parent | dfec3737b05d22e6f298bcae0a8948a4b8803ebd (diff) | |
download | rails-ea4b94a7bf707d27af44701fa44ef5f916b84e01.tar.gz rails-ea4b94a7bf707d27af44701fa44ef5f916b84e01.tar.bz2 rails-ea4b94a7bf707d27af44701fa44ef5f916b84e01.zip |
Destroy association habtm record before destroying the record itself. Fixes issue #402.
4 files changed, 29 insertions, 12 deletions
diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb index d7632b2ea9..30fc44b4c2 100644 --- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb @@ -7,24 +7,22 @@ module ActiveRecord::Associations::Builder def build reflection = super check_validity(reflection) - define_after_destroy_method + define_destroy_hook reflection end private - def define_after_destroy_method + def define_destroy_hook name = self.name - model.send(:class_eval, <<-eoruby, __FILE__, __LINE__ + 1) - def #{after_destroy_method_name} - association(#{name.to_sym.inspect}).delete_all - end - eoruby - model.after_destroy after_destroy_method_name - end - - def after_destroy_method_name - "has_and_belongs_to_many_after_destroy_for_#{name}" + model.send(:include, Module.new { + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def destroy_associations + association(#{name.to_sym.inspect}).delete_all + super + end + RUBY + }) end # TODO: These checks should probably be moved into the Reflection, and we should not be diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index f425118f59..d9cd7987b0 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -79,6 +79,8 @@ module ActiveRecord # Deletes the record in the database and freezes this instance to reflect # that no changes should be made (since they can't be persisted). def destroy + destroy_associations + if persisted? IdentityMap.remove(self) if IdentityMap.enabled? pk = self.class.primary_key @@ -284,6 +286,11 @@ module ActiveRecord end private + + # A hook to be overriden by association modules. + def destroy_associations + end + def create_or_update raise ReadOnlyRecord if readonly? result = new_record? ? create : update diff --git a/activerecord/test/cases/habtm_destroy_order_test.rb b/activerecord/test/cases/habtm_destroy_order_test.rb index f2b91d977e..2ce0de360e 100644 --- a/activerecord/test/cases/habtm_destroy_order_test.rb +++ b/activerecord/test/cases/habtm_destroy_order_test.rb @@ -16,6 +16,16 @@ class HabtmDestroyOrderTest < ActiveRecord::TestCase assert !sicp.destroyed? end + test 'should not raise error if have foreign key in the join table' do + student = Student.new(:name => "Ben Bitdiddle") + lesson = Lesson.new(:name => "SICP") + lesson.students << student + lesson.save! + assert_nothing_raised do + student.destroy + end + end + test "not destroying a student with lessons leaves student<=>lesson association intact" do # test a normal before_destroy doesn't destroy the habtm joins begin diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 4fe311b441..fd2ee23dd5 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -719,6 +719,8 @@ ActiveRecord::Schema.define do end execute "ALTER TABLE fk_test_has_fk ADD CONSTRAINT fk_name FOREIGN KEY (#{quote_column_name 'fk_id'}) REFERENCES #{quote_table_name 'fk_test_has_pk'} (#{quote_column_name 'id'})" + + execute "ALTER TABLE lessons_students ADD CONSTRAINT student_id_fk FOREIGN KEY (#{quote_column_name 'student_id'}) REFERENCES #{quote_table_name 'students'} (#{quote_column_name 'id'})" end end |