Permalink
Browse files

Setting the id of a belongs_to object updates all referenced objects [#…

…2989 state:resolved]
  • Loading branch information...
1 parent e924814 commit 7ecee054a322e214e4f285b1a8327751bd79a418 @zilkey zilkey committed with tenderlove Dec 4, 2010
@@ -1223,12 +1223,14 @@ def belongs_to(association_id, options = {})
if reflection.options[:polymorphic]
association_accessor_methods(reflection, BelongsToPolymorphicAssociation)
+ association_foreign_type_setter_method(reflection)
else
association_accessor_methods(reflection, BelongsToAssociation)
association_constructor_method(:build, reflection, BelongsToAssociation)
association_constructor_method(:create, reflection, BelongsToAssociation)
end
+ association_foreign_key_setter_method(reflection)
add_counter_cache_callbacks(reflection) if options[:counter_cache]
add_touch_callbacks(reflection, options[:touch]) if options[:touch]
@@ -1555,6 +1557,41 @@ def association_constructor_method(constructor, reflection, association_proxy_cl
end
end
+ def association_foreign_key_setter_method(reflection)
+ setters = reflect_on_all_associations(:belongs_to).map do |belongs_to_reflection|
+ if belongs_to_reflection.primary_key_name == reflection.primary_key_name
+ "association_instance_set(:#{belongs_to_reflection.name}, nil);"
+ end
+ end.compact.join
+
+ class_eval <<-FILE, __FILE__, __LINE__ + 1
+ def #{reflection.primary_key_name}=(new_id)
+ write_attribute :#{reflection.primary_key_name}, new_id
+ if #{reflection.primary_key_name}_changed?
+ #{ setters }
+ end
+ end
+ FILE
+ end
+
+ def association_foreign_type_setter_method(reflection)
+ setters = reflect_on_all_associations(:belongs_to).map do |belongs_to_reflection|
+ if belongs_to_reflection.options[:foreign_type] == reflection.options[:foreign_type]
+ "association_instance_set(:#{belongs_to_reflection.name}, nil);"
+ end
+ end.compact.join
+
+ field = reflection.options[:foreign_type]
+ class_eval <<-FILE, __FILE__, __LINE__ + 1
+ def #{field}=(new_id)
+ write_attribute :#{field}, new_id
+ if #{field}_changed?
+ #{ setters }
+ end
+ end
+ FILE
+ end
+
def add_counter_cache_callbacks(reflection)
cache_column = reflection.counter_cache_column
@@ -486,4 +486,41 @@ def test_attributes_are_being_set_when_initialized_from_belongs_to_association_w
new_firm = accounts(:signals37).build_firm(:name => 'Apple')
assert_equal new_firm.name, "Apple"
end
+
+ def test_reassigning_the_parent_id_updates_the_object
+ original_parent = Firm.create! :name => "original"
+ updated_parent = Firm.create! :name => "updated"
+
+ client = Client.new("client_of" => original_parent.id)
+ assert_equal original_parent, client.firm
+ assert_equal original_parent, client.firm_with_condition
+ assert_equal original_parent, client.firm_with_other_name
+
+ client.client_of = updated_parent.id
+ assert_equal updated_parent, client.firm
+ assert_equal updated_parent, client.firm_with_condition
+ assert_equal updated_parent, client.firm_with_other_name
+ end
+
+ def test_polymorphic_reassignment_of_associated_id_updates_the_object
+ member1 = Member.create!
+ member2 = Member.create!
+
+ sponsor = Sponsor.new("sponsorable_type" => "Member", "sponsorable_id" => member1.id)
+ assert_equal member1, sponsor.sponsorable
+
+ sponsor.sponsorable_id = member2.id
+ assert_equal member2, sponsor.sponsorable
+ end
+
+ def test_polymorphic_reassignment_of_associated_type_updates_the_object
+ member1 = Member.create!
+
+ sponsor = Sponsor.new("sponsorable_type" => "Member", "sponsorable_id" => member1.id)
+ assert_equal member1, sponsor.sponsorable
+
+ sponsor.sponsorable_type = "Firm"
+ assert_not_equal member1, sponsor.sponsorable
+ end
+
end

0 comments on commit 7ecee05

Please sign in to comment.