Morgan Grubb
2008-Jun-11 14:07 UTC
after_save filter on the join model cannot create new objects
Establishing a friend relationship with another user with a join model (user_id, friend_id). Normally this would result in one-way relationships (Jack is a friend of Jill but Jill is not a friend of Jack). To get around this I want to have an inverted entry in the join model table (not the nicest approach but I see no reason why it cannot work) so I set up my models like this: class User < ActiveRecord::Base has_many :user_friends, :dependent => :destroy has_many :friends, :through => :user_friends, :order => :first_name end class UserFriend < ActiveRecord::Base attr_accessor :final belongs_to :user belongs_to :friend, :foreign_key => :friend_id, :class_name => "User" validates_presence_of :user, :friend # Make the relationship bidirectional after_save :duplicate_inverted after_destroy :destroy_inverted protected # Create an inverted version of this record (unless one already exists) def duplicate_inverted return true if self.final unless UserFriend.exists? :user_id => friend_id, :friend_id => user_id self.class.create :user_id => friend_id, :friend_id => user_id, :final => true end end # Remove the inverted version of this object def destroy_inverted if UserFriend.exists? :user_id => friend_id, :friend_id => user_id self.class.destroy :user_id => friend_id, :friend_id => user_id end end end The UserFriend#final method exists so the iteration only happens once. What happens, though, when I run this: u1 = User.find 1 u2 = User.find 2 u1.friends.clear u1.friends << u2 User Columns (0.001914) SHOW FIELDS FROM `users` User Load (0.000986) SELECT * FROM `users` WHERE (`users`.`id` = 1) User Load (0.000980) SELECT * FROM `users` WHERE (`users`.`id` = 2) User Load (0.001556) SELECT `users`.* FROM `users` INNER JOIN user_friends ON users.id = user_friends.friend_id WHERE ((`user_friends`.user_id = 1)) ORDER BY first_name SQL (0.000288) BEGIN UserFriend Columns (0.000853) SHOW FIELDS FROM `user_friends` User Load (0.000990) SELECT * FROM `users` WHERE (`users`.`id` = 1) User Load (0.000960) SELECT * FROM `users` WHERE (`users`.`id` = 2) *** UserFriend Create (0.000443) INSERT INTO `user_friends` (`updated_at`, `user_id`, `friend_id`, `created_at`) VALUES(''2008-06-11 15:04:46'', 1, 2, ''2008-06-11 15:04:46'') UserFriend Exists (0.000477) SELECT `user_friends`.id FROM `user_friends` WHERE (`user_friends`.`user_id` = 2 AND `user_friends`.`friend_id` = 1) LIMIT 1 User Load (0.000993) SELECT * FROM `users` WHERE (`users`.`id` = 1) User Load (0.000967) SELECT * FROM `users` WHERE (`users`.`id` = 2) *** UserFriend Create (0.000396) INSERT INTO `user_friends` (`updated_at`, `user_id`, `friend_id`, `created_at`) VALUES(''2008-06-11 15:04:46'', 1, 2, ''2008-06-11 15:04:46'') SQL (0.020969) COMMIT I''ve put *** in front of the two important rows. The first creates the requested object, the second creates the inverted one. However, the second insert has user_id and friend_id set to the same values as the first insertion? I tested this by replacing unless UserFriend.exists? :user_id => friend_id, :friend_id => user_id self.class.create :user_id => friend_id, :friend_id => user_id, :final => true end with unless UserFriend.exists? :user_id => friend_id, :friend_id => user_id self.class.create :user_id => 5, :friend_id => 5, :final => true end and the results were exactly the same. This leads me to believe there is some sort of with_scope or something going one which is appending those values to my create call but I don''t know how to find out whether or not this is the case. Can anyone shine some light on this behaviour? Cheers, Morgan Grubb. -- -------------------------------------------------------------------------- Morgan Grubb - Just Landed General Tel: +34 91 590 2611 morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org -------------------------------------------------------------------------- http://www.justlanded.com - Helping people abroad! 30 countries, in up to 8 languages, more to come... -------------------------------------------------------------------------- --~--~---------~--~----~------------~-------~--~----~ 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-Jun-11 14:11 UTC
Re: after_save filter on the join model cannot create new objects
On 11 Jun 2008, at 15:07, Morgan Grubb wrote:> > > I tested this by replacing > unless UserFriend.exists? :user_id => friend_id, :friend_id => > user_id > self.class.create :user_id => friend_id, :friend_id => > user_id, :final => true > end > > with > unless UserFriend.exists? :user_id => friend_id, :friend_id => > user_id > self.class.create :user_id => 5, :friend_id => 5, :final => > true > end > > and the results were exactly the same. This leads me to believe > there is some sort of with_scope or something going one which is > appending those values to my create call but I don''t know how to > find out whether or not this is the case. >That sounds eminently plausible. with_exclusive_scope might help you out. Fred> Can anyone shine some light on this behaviour? > > > Cheers, > Morgan Grubb. > -- > -------------------------------------------------------------------------- > Morgan Grubb - Just Landed > General Tel: +34 91 590 2611 > morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org > -------------------------------------------------------------------------- > http://www.justlanded.com - Helping people abroad! > 30 countries, in up to 8 languages, more to come... > -------------------------------------------------------------------------- > >--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Morgan Grubb
2008-Jun-11 14:39 UTC
Re: after_save filter on the join model cannot create new objects
2008/6/11 Frederick Cheung <frederick.cheung-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:> > > On 11 Jun 2008, at 15:07, Morgan Grubb wrote: > > > > > > > I tested this by replacing > > unless UserFriend.exists? :user_id => friend_id, :friend_id => > > user_id > > self.class.create :user_id => friend_id, :friend_id => > > user_id, :final => true > > end > > > > with > > unless UserFriend.exists? :user_id => friend_id, :friend_id => > > user_id > > self.class.create :user_id => 5, :friend_id => 5, :final => > > true > > end > > > > and the results were exactly the same. This leads me to believe > > there is some sort of with_scope or something going one which is > > appending those values to my create call but I don''t know how to > > find out whether or not this is the case. > > > That sounds eminently plausible. with_exclusive_scope might help you > out. >Thanks for that. I''ve been trying a few variants and running into issues. It seems to me this UserFriend.send :with_exclusive_scope, { :user_id => friend_id, :friend_id => user_id } do UserFriend.create :final => true unless UserFriend.exists? end should work but it leads to ArgumentError: Unknown key(s): user_id, friend_id I can see why they decided to make with_scope a protected method. It''s a real pain in the butt. I''ll keep trying but if you can see can what I''m doing wrong I''d love to hear it. Cheers.> > Fred > > Can anyone shine some light on this behaviour? > > > > > > Cheers, > > Morgan Grubb. > > -- > > > -------------------------------------------------------------------------- > > Morgan Grubb - Just Landed > > General Tel: +34 91 590 2611 > > morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org > > > -------------------------------------------------------------------------- > > http://www.justlanded.com - Helping people abroad! > > 30 countries, in up to 8 languages, more to come... > > > -------------------------------------------------------------------------- > > > > > > > >-- -------------------------------------------------------------------------- Morgan Grubb - Just Landed General Tel: +34 91 590 2611 morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org -------------------------------------------------------------------------- http://www.justlanded.com - Helping people abroad! 30 countries, in up to 8 languages, more to come... -------------------------------------------------------------------------- --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Morgan Grubb
2008-Jun-11 14:41 UTC
Re: after_save filter on the join model cannot create new objects
> > >> > and the results were exactly the same. This leads me to believe >> > there is some sort of with_scope or something going one which is >> > appending those values to my create call but I don''t know how to >> > find out whether or not this is the case. >> > >> That sounds eminently plausible. with_exclusive_scope might help you >> out. >> > > Thanks for that. > > I''ve been trying a few variants and running into issues. It seems to me > this > > UserFriend.send :with_exclusive_scope, { :user_id => friend_id, > :friend_id => user_id } do > UserFriend.create :final => true unless UserFriend.exists? > end > > should work but it leads to > > ArgumentError: Unknown key(s): user_id, friend_id > > I can see why they decided to make with_scope a protected method. It''s a > real pain in the butt. > > I''ll keep trying but if you can see can what I''m doing wrong I''d love to > hear it. > >Sorry, the error that specific version leads to is TypeError: can''t dup Fixnum Which is when I replaced friend.id with friend_id and got the unknown keys error. Cheers. -- -------------------------------------------------------------------------- Morgan Grubb - Just Landed General Tel: +34 91 590 2611 morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org -------------------------------------------------------------------------- http://www.justlanded.com - Helping people abroad! 30 countries, in up to 8 languages, more to come... -------------------------------------------------------------------------- --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Morgan Grubb
2008-Jun-11 14:44 UTC
Re: after_save filter on the join model cannot create new objects
2008/6/11 Morgan Grubb <morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org>:> >>> > and the results were exactly the same. This leads me to believe >>> > there is some sort of with_scope or something going one which is >>> > appending those values to my create call but I don''t know how to >>> > find out whether or not this is the case. >>> > >>> That sounds eminently plausible. with_exclusive_scope might help you >>> out. >>> >> >> Thanks for that. >> >> I''ve been trying a few variants and running into issues. It seems to me >> this >> >> UserFriend.send :with_exclusive_scope, { :user_id => friend_id, >> :friend_id => user_id } do >> UserFriend.create :final => true unless UserFriend.exists? >> end >> >> should work but it leads to >> >> ArgumentError: Unknown key(s): user_id, friend_id >> >> I can see why they decided to make with_scope a protected method. It''s a >> real pain in the butt. >> >> I''ll keep trying but if you can see can what I''m doing wrong I''d love to >> hear it. >> >> > Sorry, the error that specific version leads to is > > TypeError: can''t dup Fixnum > > Which is when I replaced friend.id with friend_id and got the unknown keys > error. > >I''m on fire today. Just realised that with_scope takes a hash of actions and params, not params directly. I''ll check this out now. Cheers. -- -------------------------------------------------------------------------- Morgan Grubb - Just Landed General Tel: +34 91 590 2611 morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org -------------------------------------------------------------------------- http://www.justlanded.com - Helping people abroad! 30 countries, in up to 8 languages, more to come... -------------------------------------------------------------------------- --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Morgan Grubb
2008-Jun-11 14:57 UTC
Re: after_save filter on the join model cannot create new objects
2008/6/11 Morgan Grubb <morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org>:> > > 2008/6/11 Morgan Grubb <morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org>: > >> >>>> > and the results were exactly the same. This leads me to believe >>>> > there is some sort of with_scope or something going one which is >>>> > appending those values to my create call but I don''t know how to >>>> > find out whether or not this is the case. >>>> > >>>> That sounds eminently plausible. with_exclusive_scope might help you >>>> out. >>>> >>> >>> Thanks for that. >>> >>> I''ve been trying a few variants and running into issues. It seems to me >>> this >>> >>> UserFriend.send :with_exclusive_scope, { :user_id => friend_id, >>> :friend_id => user_id } do >>> UserFriend.create :final => true unless UserFriend.exists? >>> end >>> >>> should work but it leads to >>> >>> ArgumentError: Unknown key(s): user_id, friend_id >>> >>> I can see why they decided to make with_scope a protected method. It''s a >>> real pain in the butt. >>> >>> I''ll keep trying but if you can see can what I''m doing wrong I''d love to >>> hear it. >>> >>> >> Sorry, the error that specific version leads to is >> >> TypeError: can''t dup Fixnum >> >> Which is when I replaced friend.id with friend_id and got the unknown >> keys error. >> >> > I''m on fire today. Just realised that with_scope takes a hash of actions > and params, not params directly. > > I''ll check this out now. >Bang on. The final working bi-directional friendship version: class UserFriend < ActiveRecord::Base attr_accessor :final belongs_to :user belongs_to :friend, :foreign_key => :friend_id, :class_name => "User" validates_presence_of :user, :friend # Make the relationship bidirectional after_save :duplicate_inverted after_destroy :destroy_inverted protected # Create an inverted version of this record (unless one already exists) def duplicate_inverted return true if self.final UserFriend.send(:with_exclusive_scope, :find => {}, :create => {}) do unless UserFriend.exists? :user_id => friend_id, :friend_id => user_id UserFriend.create :final => true, :user_id => friend_id, :friend_id => user_id end end end # Remove the inverted version of this object def destroy_inverted if UserFriend.exists? :user_id => self.friend_id, :friend_id => self.user_id UserFriend.destroy_all :user_id => self.friend_id, :friend_id => self.user_id end end end Thanks for your help. -- -------------------------------------------------------------------------- Morgan Grubb - Just Landed General Tel: +34 91 590 2611 morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org -------------------------------------------------------------------------- http://www.justlanded.com - Helping people abroad! 30 countries, in up to 8 languages, more to come... -------------------------------------------------------------------------- --~--~---------~--~----~------------~-------~--~----~ 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-Jun-11 14:58 UTC
Re: after_save filter on the join model cannot create new objects
On 11 Jun 2008, at 15:44, Morgan Grubb wrote:> > Sorry, the error that specific version leads to is > > TypeError: can''t dup Fixnum > > Which is when I replaced friend.id with friend_id and got the > unknown keys error. > > > I''m on fire today. Just realised that with_scope takes a hash of > actions and params, not params directly. > > I''ll check this out now. >conceivably you could just do with_exclusive_scope do ... end Fred> > > Cheers. > > > -- > -------------------------------------------------------------------------- > Morgan Grubb - Just Landed > General Tel: +34 91 590 2611 > morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org > -------------------------------------------------------------------------- > http://www.justlanded.com - Helping people abroad! > 30 countries, in up to 8 languages, more to come... > -------------------------------------------------------------------------- > >--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Morgan Grubb
2008-Jun-11 15:08 UTC
Re: after_save filter on the join model cannot create new objects
2008/6/11 Frederick Cheung <frederick.cheung-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:> > > On 11 Jun 2008, at 15:44, Morgan Grubb wrote: > > > > > Sorry, the error that specific version leads to is > > > > TypeError: can''t dup Fixnum > > > > Which is when I replaced friend.id with friend_id and got the > > unknown keys error. > > > > > > I''m on fire today. Just realised that with_scope takes a hash of > > actions and params, not params directly. > > > > I''ll check this out now. > > > conceivably you could just do > with_exclusive_scope do > ... > end >You''re right. Works fine. Cheers. -- -------------------------------------------------------------------------- Morgan Grubb - Just Landed General Tel: +34 91 590 2611 morgan.grubb-9pJevV/ekkYyY3YROqfsYA@public.gmane.org -------------------------------------------------------------------------- http://www.justlanded.com - Helping people abroad! 30 countries, in up to 8 languages, more to come... -------------------------------------------------------------------------- --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---