diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb index b78bd5d9311cd..8073ebaf9f699 100644 --- a/activerecord/lib/active_record/associations/has_one_through_association.rb +++ b/activerecord/lib/active_record/associations/has_one_through_association.rb @@ -8,11 +8,10 @@ def create_through_record(new_value) #nodoc: current_object = @owner.send(@reflection.through_reflection.name) if current_object - klass.destroy(current_object) - @owner.clear_association_cache + current_object.update_attributes(construct_join_attributes(new_value)) + else + @owner.send(@reflection.through_reflection.name, klass.send(:create, construct_join_attributes(new_value))) end - - @owner.send(@reflection.through_reflection.name, klass.send(:create, construct_join_attributes(new_value))) end private diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb index ff4021fe027d3..7d418de96515c 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -3,9 +3,11 @@ require 'models/member' require 'models/membership' require 'models/sponsor' +require 'models/organization' +require 'models/member_detail' class HasOneThroughAssociationsTest < ActiveRecord::TestCase - fixtures :members, :clubs, :memberships, :sponsors + fixtures :members, :clubs, :memberships, :sponsors, :organizations def setup @member = members(:groucho) @@ -120,4 +122,40 @@ def test_has_one_through_proxy_should_respond_to_private_methods_via_send clubs(:moustache_club).send(:private_method) @member.club.send(:private_method) end + + def test_assigning_to_has_one_through_preserves_decorated_join_record + @organization = organizations(:nsa) + assert_difference 'MemberDetail.count', 1 do + @member_detail = MemberDetail.new(:extra_data => 'Extra') + @member.member_detail = @member_detail + @member.organization = @organization + end + assert_equal @organization, @member.organization + assert @organization.members.include?(@member) + assert_equal 'Extra', @member.member_detail.extra_data + end + + def test_reassigning_has_one_through + @organization = organizations(:nsa) + @new_organization = organizations(:discordians) + + assert_difference 'MemberDetail.count', 1 do + @member_detail = MemberDetail.new(:extra_data => 'Extra') + @member.member_detail = @member_detail + @member.organization = @organization + end + assert_equal @organization, @member.organization + assert_equal 'Extra', @member.member_detail.extra_data + assert @organization.members.include?(@member) + assert !@new_organization.members.include?(@member) + + assert_no_difference 'MemberDetail.count' do + @member.organization = @new_organization + end + assert_equal @new_organization, @member.organization + assert_equal 'Extra', @member.member_detail.extra_data + assert !@organization.members.include?(@member) + assert @new_organization.members.include?(@member) + end + end diff --git a/activerecord/test/fixtures/organizations.yml b/activerecord/test/fixtures/organizations.yml new file mode 100644 index 0000000000000..25295bff87738 --- /dev/null +++ b/activerecord/test/fixtures/organizations.yml @@ -0,0 +1,5 @@ +nsa: + name: No Such Agency +discordians: + name: Discordians + diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index 688725f200754..77a37abb387f3 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -6,4 +6,6 @@ class Member < ActiveRecord::Base has_one :favourite_club, :through => :memberships, :conditions => ["memberships.favourite = ?", true], :source => :club has_one :sponsor, :as => :sponsorable has_one :sponsor_club, :through => :sponsor + has_one :member_detail + has_one :organization, :through => :member_detail end \ No newline at end of file diff --git a/activerecord/test/models/member_detail.rb b/activerecord/test/models/member_detail.rb new file mode 100644 index 0000000000000..e7314545568e8 --- /dev/null +++ b/activerecord/test/models/member_detail.rb @@ -0,0 +1,4 @@ +class MemberDetail < ActiveRecord::Base + belongs_to :member + belongs_to :organization +end diff --git a/activerecord/test/models/organization.rb b/activerecord/test/models/organization.rb new file mode 100644 index 0000000000000..d79d5037c8053 --- /dev/null +++ b/activerecord/test/models/organization.rb @@ -0,0 +1,4 @@ +class Organization < ActiveRecord::Base + has_many :member_details + has_many :members, :through => :member_details +end \ No newline at end of file diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index ab5c7c520b9f8..6217e3bc1c69b 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -197,6 +197,12 @@ def create_table(*args, &block) t.string :name end + create_table :member_details, :force => true do |t| + t.integer :member_id + t.integer :organization_id + t.string :extra_data + end + create_table :memberships, :force => true do |t| t.datetime :joined_on t.integer :club_id, :member_id @@ -249,6 +255,10 @@ def create_table(*args, &block) t.integer :shipping_customer_id end + create_table :organizations, :force => true do |t| + t.string :name + end + create_table :owners, :primary_key => :owner_id ,:force => true do |t| t.string :name end