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

Changeset 8043

Show
Ignore:
Timestamp:
10/27/07 18:51:32 (1 year ago)
Author:
bitsweat
Message:

Fix has_many :through delete with custom foreign keys. Closes #6466.

Files:

Legend:

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

    r8036 r8043  
    11*SVN* 
     2 
     3* Fix has_many :through delete with custom foreign keys.  #6466 [naffis] 
    24 
    35* Foxy fixtures, from rathole (http://svn.geeksomnia.com/rathole/trunk/README) 
  • trunk/activerecord/lib/active_record/associations.rb

    r8006 r8043  
    4747    def initialize(owner, reflection) 
    4848      super("Cannot associate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to create the has_many :through record associating them.") 
     49    end 
     50  end 
     51 
     52  class HasManyThroughCantDissociateNewRecords < ActiveRecordError #:nodoc: 
     53    def initialize(owner, reflection) 
     54      super("Cannot dissociate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to delete the has_many :through record associating them.") 
    4955    end 
    5056  end 
  • trunk/activerecord/lib/active_record/associations/has_many_through_association.rb

    r7913 r8043  
    7272        records = flatten_deeper(records) 
    7373        records.each { |associate| raise_on_type_mismatch(associate) } 
    74         records.reject! { |associate| @target.delete(associate) if associate.new_record? } 
    75         return if records.empty? 
    76          
    77         @delete_join_finder ||= "find_all_by_#{@reflection.source_reflection.association_foreign_key}" 
     74 
    7875        through = @reflection.through_reflection 
    79         through.klass.transaction do 
    80           records.each do |associate| 
    81             joins = @owner.send(through.name).send(@delete_join_finder, associate.id) 
    82             @owner.send(through.name).delete(joins) 
     76        raise ActiveRecord::HasManyThroughCantDissociateNewRecords.new(@owner, through) if @owner.new_record? 
     77 
     78        load_target 
     79 
     80        klass = through.klass 
     81        klass.transaction do 
     82          flatten_deeper(records).each do |associate| 
     83            raise_on_type_mismatch(associate) 
     84            raise ActiveRecord::HasManyThroughCantDissociateNewRecords.new(@owner, through) unless associate.respond_to?(:new_record?) && !associate.new_record? 
     85 
     86            @owner.send(through.name).proxy_target.delete(klass.delete_all(construct_join_attributes(associate))) 
    8387            @target.delete(associate) 
    8488          end 
    8589        end 
     90 
     91        self 
    8692      end 
    8793 
  • trunk/activerecord/test/associations/join_model_test.rb

    r7913 r8043  
    1010require 'fixtures/vertex' 
    1111require 'fixtures/edge' 
     12require 'fixtures/book' 
     13require 'fixtures/citation' 
    1214 
    1315class AssociationsJoinModelTest < Test::Unit::TestCase 
    1416  self.use_transactional_fixtures = false 
    15   fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items 
     17  fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books 
    1618 
    1719  def test_has_many 
     
    477479  end 
    478480 
     481  def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id 
     482    count = books(:awdr).references.count 
     483    references_before = books(:awdr).references 
     484    book = Book.create!(:name => 'Getting Real') 
     485    book_awdr = books(:awdr) 
     486    book_awdr.references << book 
     487    assert_equal(count + 1, book_awdr.references(true).size) 
     488 
     489    assert_nothing_raised { book_awdr.references.delete(book) } 
     490    assert_equal(count, book_awdr.references.size) 
     491    assert_equal(count, book_awdr.references(true).size) 
     492    assert_equal(references_before.sort, book_awdr.references.sort) 
     493  end 
     494 
    479495  def test_delete_associate_when_deleting_from_has_many_through 
    480496    count = posts(:thinking).tags.count 
  • trunk/activerecord/test/fixtures/db_definitions/schema.rb

    r8036 r8043  
    291291  end 
    292292 
     293  create_table :books, :force => true do |t| 
     294    t.column :name, :string 
     295  end 
     296 
     297  create_table :citations, :force => true do |t| 
     298    t.column :book1_id, :integer 
     299    t.column :book2_id, :integer 
     300  end 
     301 
    293302  create_table :inept_wizards, :force => true do |t| 
    294303    t.column :name, :string, :null => false