Still Having Problems With :through When Going To Same Table

I am having a problem with doing a :through that goes back to the same
table.

The following are my two classes:

class User < ActiveRecord::Base
has_many :spanks
has_many :spanked, :through => :spanks, :source => :spanked_user
has_many :was_spanked_by, :through => :spanks, :source => :user
end

class Spank < ActiveRecord::Base
belongs_to :spanker, :class_name => “User”, :foreign_key => “user_id”
belongs_to :spankee, :class_name => “User”, :foreign_key =>
“spanked_user_id”
end

db_table:spanks
id | user_id | spanked_user_id | created_at | updated_at

I want to be able to make statemets like:

john = User.find_by_nickname(“john”)
john.spanked
john.was_spanked_by

Can I do this without using a :finder_sql?

The above does not work… but the following does:

john.spanks
spank = Spank.find(1)
spank.spankee
spank.spanker

Help… help… I get the following error:

ActiveRecord::HasManyThroughSourceAssociationNotFoundError:ActiveRecord::HasManyThroughSourceAssociationNotFoundError


John K.
[email protected]

http://www.kopanas.com

http://www.soen.info

John K. wrote:

I am having a problem with doing a :through that goes back to the same table.

Try this…

class User < ActiveRecord::Base
has_many :spanks_as_spankee, :foreign_key=>‘spanked_user_id’,
:class_name => ‘Spank’
has_many :spanks_as_spanker, :foreign_key=>‘user_id’, :class_name =>
‘Spank’
has_many :spanked, :through => :spanks_as_spankee
has_many :was_spanked_by, :through => :spanks_as_spanker
end

although, if it were my app, I would make some small association and
column name changes as well, so that…

class User < ActiveRecord::Base
has_many :spanks_as_spankee, :foreign_key=>‘spankee_id’, :class_name
=> ‘Spank’
has_many :spanks_as_spanker, :foreign_key=>‘spanker_id’, :class_name
=> ‘Spank’
has_many :spankees, :through => :spanks_as_spankee
has_many :spankers, :through => :spanks_as_spanker
end

class Spank < ActiveRecord::Base
belongs_to :spanker, :class_name => “User”, :foreign_key =>
“spanker_id”
belongs_to :spankee, :class_name => “User”, :foreign_key =>
“spankee_id”
end

Note: I haven’t actually tested the above, but I’ve done similar and it
works great. Credit goes to Josh S. for showing me how to do self
referential :throughs a while back via his blog.
http://blog.hasmanythrough.com/

Jon G. wrote:

has_many :spanked, :through => :spanks_as_spankee
has_many :spankees, :through => :spanks_as_spankee
works great. Credit goes to Josh S. for showing me how to do self
referential :throughs a while back via his blog.
http://blog.hasmanythrough.com/

Whoops, got an association backwards in the alternate option above. This
is what I meant…

class User < ActiveRecord::Base
has_many :spanks_as_spankee, :foreign_key=>‘spankee_id’, :class_name
=> ‘Spank’
has_many :spanks_as_spanker, :foreign_key=>‘spanker_id’, :class_name
=> ‘Spank’
has_many :spankers, :through => :spanks_as_spankee
has_many :spankees, :through => :spanks_as_spanker
end

Worked great! Thanks Jon… but now I have a couple questions for you
if you don’t mind :-).

  1. why is :through point to a has_many relatioship? I thought it
    usually points to an object/table.

  2. If I change spankers to spanked_by it breaks… why?

Thanks again for your help :-).

On 11/2/06, Jon G. [email protected] wrote:

column name changes as well, so that…

has_many :spankees, :through => :spanks_as_spanker
end


John K.
[email protected]

http://www.kopanas.com

http://www.soen.info

John K. wrote:

Josh S., or anyone else more familiar with how this technique works,
can probably provide much better answers. But…

  1. Yes, normally it would point directly to the join model/table.
    However, to do more complex stuff (like self referential has_many
    :throughs), sometimes you gotta break out the magic wand and wave it
    with enthusiasm.

  2. I just guessing, but maybe the ‘_by’ suffix is getting some other
    Rails magic applied to it. Try changing it to :spanked_bx, and see if
    that helps. Either way, someone more familiar than I with the Rails
    internals might be able to explain it.