Ticket #6466: fix_add_and_delete_for_has_many_through.diff
| File fix_add_and_delete_for_has_many_through.diff, 6.9 kB (added by naffis, 2 years ago) |
|---|
-
test/associations/join_model_test.rb
old new 6 6 require 'fixtures/author' 7 7 require 'fixtures/category' 8 8 require 'fixtures/categorization' 9 require 'fixtures/book' 10 require 'fixtures/citation' 9 11 10 12 class AssociationsJoinModelTest < Test::Unit::TestCase 11 13 self.use_transactional_fixtures = false 12 fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites 14 fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :books 13 15 14 16 def test_has_many 15 17 assert authors(:david).categories.include?(categories(:general)) … … 424 426 tags = posts(:thinking).tags 425 427 assert_equal tags, posts(:thinking).tags.push(tags(:general)) 426 428 end 429 430 def test_delete_associate_when_deleting_from_has_many_through_with_non_standard_id 431 count = books(:awdr).references.count 432 references_before = books(:awdr).references 433 book = Book.create!(:name => 'Getting Real') 434 book_awdr = books(:awdr) 435 book_awdr.references << book 436 assert_equal(count + 1, book_awdr.references(true).size) 427 437 438 assert_nothing_raised { book_awdr.references.delete(book) } 439 assert_equal(count, book_awdr.references.size) 440 assert_equal(count, book_awdr.references(true).size) 441 assert_equal(references_before.sort, book_awdr.references.sort) 442 end 443 428 444 def test_delete_associate_when_deleting_from_has_many_through 429 445 count = posts(:thinking).tags.count 430 446 tags_before = posts(:thinking).tags -
test/fixtures/citation.rb
old new 1 class Citation < ActiveRecord::Base 2 belongs_to :reference_of, :class_name => "Book", :foreign_key => :book2_id 3 belongs_to :book1, :class_name => "Book", :foreign_key => :book1_id 4 belongs_to :book2, :class_name => "Book", :foreign_key => :book2_id 5 6 end -
test/fixtures/db_definitions/schema.rb
old new 57 57 create_table :lock_with_custom_column_without_defaults, :force => true do |t| 58 58 t.column :custom_lock_version, :integer 59 59 end 60 61 create_table :books, :force => true do |t| 62 t.column :name, :string 63 end 64 65 create_table :citations, :id => false, :force => true do |t| 66 t.column :book1_id, :integer 67 t.column :book2_id, :integer 68 end 69 60 70 end -
test/fixtures/book.rb
old new 1 class Book < ActiveRecord::Base 2 has_many :citations, :foreign_key => 'book1_id' 3 has_many :references, :through => :citations, :source => :reference_of, :uniq => true 4 5 end -
test/fixtures/books.yml
old new 1 awdr: 2 id: 1 3 name: "Agile Web Development with Rails" 4 5 rfr: 6 id: 2 7 name: "Ruby for Rails" -
lib/active_record/associations/has_many_through_association.rb
old new 71 71 72 72 # Remove +records+ from this association. Does not destroy +records+. 73 73 def delete(*records) 74 records = flatten_deeper(records) 75 records.each { |associate| raise_on_type_mismatch(associate) } 76 records.reject! { |associate| @target.delete(associate) if associate.new_record? } 77 return if records.empty? 78 79 @delete_join_finder ||= "find_all_by_#{@reflection.source_reflection.association_foreign_key}" 80 through = @reflection.through_reflection 81 through.klass.transaction do 82 records.each do |associate| 83 joins = @owner.send(through.name).send(@delete_join_finder, associate.id) 84 @owner.send(through.name).delete(joins) 85 @target.delete(associate) 86 end 87 end 88 end 74 return if records.empty? 75 records.each { |associate| raise_on_type_mismatch(associate) } 76 through = @reflection.through_reflection 77 raise ActiveRecord::HasManyThroughCantDisassociateNewRecords.new(@owner, through) if @owner.new_record? 89 78 79 load_target 80 81 klass = through.klass 82 klass.transaction do 83 flatten_deeper(records).each do |associate| 84 raise_on_type_mismatch(associate) 85 raise ActiveRecord::HasManyThroughCantDisassociateNewRecords.new(@owner, through) unless associate.respond_to?(:new_record?) && !associate.new_record? 86 87 @owner.send(@reflection.through_reflection.name).proxy_target.delete(klass.delete_all(construct_join_attributes(associate))) 88 @target.delete(associate) 89 end 90 end 91 92 self 93 end 94 90 95 def build(attrs = nil) 91 96 raise ActiveRecord::HasManyThroughCantAssociateNewRecords.new(@owner, @reflection.through_reflection) 92 97 end … … 138 143 139 144 # Construct attributes for :through pointing to owner and associate. 140 145 def construct_join_attributes(associate) 141 construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection. association_foreign_key=> associate.id)146 construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.primary_key_name => associate.id) 142 147 end 143 148 144 149 # Associate attributes pointing to owner, quoted. -
lib/active_record/associations.rb
old new 44 44 end 45 45 end 46 46 47 class HasManyThroughCantDisassociateNewRecords < ActiveRecordError #:nodoc: 48 def initialize(owner, reflection) 49 super("Cannot disassociate 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.") 50 end 51 end 52 47 53 class EagerLoadPolymorphicError < ActiveRecordError #:nodoc: 48 54 def initialize(reflection) 49 55 super("Can not eagerly load the polymorphic association #{reflection.name.inspect}")