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 -~----------~----~----~----~------~----~------~--~---