Matt Westcott
2008-May-07 08:53 UTC
Assigning to the foreign key on a belongs_to association
I''ve encountered what seems like an odd omission in the behaviour of belongs_to associations: if you assign to the foreign key attribute, it doesn''t update the associated object (or mark a previously loaded one as stale) until you explicitly save or reload it. Let''s say we have a Company model, which belongs_to :city : torchbox = Company.find_by_name(''Torchbox'') => #<Company id: 1, name: "Torchbox", city_id: 1> torchbox.city => #<City id: 1, name: "Oxford"> torchbox.city_id = 2 => 2 torchbox.city => #<City id: 1, name: "Oxford"> (Would have expected City id: 2 to be returned here...) I''ve come up with a 6-line patch (see below) and accompanying plugin to fix this, but I get the feeling that for something so elementary to have gone unfixed for so long, there must be some perceived good reason why it works the way it does. If so, what''s the reason? If not, I''ll file this on Lighthouse. - Matt diff --git a/activerecord/lib/active_record/associations.rb b/ activerecord/lib/active_record/associations.rb index 0809b27..7135e50 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1094,6 +1094,13 @@ module ActiveRecord instance_variable_set(ivar, new_value.nil? ? nil : association) end + if association_proxy_class == BelongsToAssociation + define_method("#{reflection.primary_key_name}=") do | target_id| + instance_variable_set(ivar, nil) + self["#{reflection.primary_key_name}"] = target_id + end + end + define_method("set_#{reflection.name}_target") do |target| return if target.nil? and association_proxy_class =BelongsToAssociation association = association_proxy_class.new(self, reflection) diff --git a/activerecord/test/cases/associations/ belongs_to_associations_test.rb b/activerecord/test/cases/associations/ belongs_to_associations_test.rb index b8ec911..c130db2 100644 --- a/activerecord/test/cases/associations/ belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/ belongs_to_associations_test.rb @@ -45,6 +45,13 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal apple.id, citibank.firm_id end + def test_foreign_key_assignment + signals37 = accounts(:signals37) + assert_equal companies(:first_firm), signals37.firm + signals37.firm_id = companies(:another_firm).id + assert_equal companies(:another_firm), signals37.firm + end + def test_no_unexpected_aliasing first_firm = companies(:first_firm) another_firm = companies(:another_firm) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Michael Koziarski
2008-May-09 02:42 UTC
Re: Assigning to the foreign key on a belongs_to association
On Wed, May 7, 2008 at 8:53 PM, Matt Westcott <matthew@west.co.tt> wrote:> > I''ve encountered what seems like an odd omission in the behaviour of > belongs_to associations: if you assign to the foreign key attribute, > it doesn''t update the associated object (or mark a previously loaded > one as stale) until you explicitly save or reload it. > > Let''s say we have a Company model, which belongs_to :city : > > torchbox = Company.find_by_name(''Torchbox'') > => #<Company id: 1, name: "Torchbox", city_id: 1> > torchbox.city > => #<City id: 1, name: "Oxford"> > torchbox.city_id = 2 > => 2 > torchbox.city > => #<City id: 1, name: "Oxford"> > > (Would have expected City id: 2 to be returned here...) > > I''ve come up with a 6-line patch (see below) and accompanying plugin > to fix this, but I get the feeling that for something so elementary to > have gone unfixed for so long, there must be some perceived good > reason why it works the way it does. If so, what''s the reason? If not, > I''ll file this on Lighthouse.AFAIK There''s no explicit reason that this hasn''t been fixed. There are a few catches though: * You''ll have to make sure your new method plays nice with the attribute_methods stuff which does caching (not all primary keys are ints) * It''ll have to work right when people have already defined their own mutator too. So when you attach your patch, make sure you have tests for that stuff. -- Cheers Koz --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---