Matt Westcott
2008-May-07 00:23 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? And if not, is this a patch that''s worth pushing through the official channels? - 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 == BelongsToAssociat 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: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-May-07 00:55 UTC
Re: Assigning to the foreign key on a belongs_to association
rails-core is the place to ask this sort of thing! Fred On 7 May 2008, at 01:23, Matt Westcott 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? And if > not, is this a patch that''s worth pushing through the official > channels? > > - 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 > == BelongsToAssociat 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: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Possibly Parallel Threads
- Possible bug
- [Bug 2496] New: sshd hangs when using AuthorizedKeysCommand
- Nokia N80 and asterisk?
- Dynamic fields and AAF
- Counterintuitive behavior in ActiveRecord I was implementing dirty checking for an application, and I found something that is a little counterintuitive. Let me start with a quick quiz: bob=User.find(1) alice=User.find(2) trip=Trip.new trip.driver=bob old_