Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 2940

Show
Ignore:
Timestamp:
11/08/05 10:19:09 (3 years ago)
Author:
bitsweat
Message:

Destroy associated has_and_belongs_to_many records after all before_destroy callbacks but before destroy. This allows you to act on the habtm association as you please while preserving referential integrity. Closes #2065.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/CHANGELOG

    r2939 r2940  
    11*SVN* 
     2 
     3* Destroy associated has_and_belongs_to_many records after all before_destroy callbacks but before destroy.  This allows you to act on the habtm association as you please while preserving referential integrity.  #2065 [larrywilliams1@gmail.com, sam.kirchmeier@gmail.com, elliot@townx.org, Jeremy Kemper] 
    24 
    35* Deprecate the old, confusing :exclusively_dependent option in favor of :dependent => :delete_all.  [Jeremy Kemper] 
  • trunk/activerecord/lib/active_record/associations.rb

    r2939 r2940  
    653653        collection_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, HasAndBelongsToManyAssociation) 
    654654 
    655         before_destroy_sql = "DELETE FROM #{options[:join_table]} WHERE #{association_class_primary_key_name} = \\\#{self.quoted_id}" 
    656         module_eval(%{before_destroy "self.connection.delete(%{#{before_destroy_sql}})"}) # " 
     655        # Don't use a before_destroy callback since users' before_destroy 
     656        # callbacks will be executed after the association is wiped out. 
     657        old_method = "destroy_without_habtm_shim_for_#{association_name}" 
     658        class_eval <<-end_eval 
     659          alias_method :#{old_method}, :destroy_without_callbacks 
     660          def destroy_without_callbacks 
     661            #{association_name}.clear 
     662            #{old_method} 
     663          end 
     664        end_eval 
     665 
    657666        add_association_callbacks(association_name, options) 
    658667         
  • trunk/activerecord/test/associations_test.rb

    r2872 r2940  
    12471247 
    12481248  def test_removing_associations_on_destroy 
    1249     Developer.find(1).destroy 
    1250     assert Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty? 
    1251   end 
    1252    
     1249    david = DeveloperWithBeforeDestroyRaise.find(1) 
     1250    assert !david.projects.empty? 
     1251    assert_nothing_raised { david.destroy } 
     1252    assert david.projects.empty? 
     1253    assert DeveloperWithBeforeDestroyRaise.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty? 
     1254  end 
     1255 
    12531256  def test_additional_columns_from_join_table 
    12541257    # SQL Server doesn't have a separate column type just for dates,  
  • trunk/activerecord/test/fixtures/developer.rb

    r2895 r2940  
    2929  composed_of :salary, :class_name => 'DeveloperSalary', :mapping => [%w(salary amount)] 
    3030end 
     31 
     32class DeveloperWithBeforeDestroyRaise < ActiveRecord::Base 
     33  self.table_name = 'developers' 
     34  has_and_belongs_to_many :projects, :join_table => 'developers_projects', :foreign_key => 'developer_id' 
     35  before_destroy :raise_if_projects_empty! 
     36 
     37  def raise_if_projects_empty! 
     38    raise if projects.empty? 
     39  end 
     40end