Still Having Problems With :through When Going To Same Table... Help... please :-(

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 Kopanas 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 Susser for showing me how to do self
referential :throughs a while back via his blog.
http://blog.hasmanythrough.com/

Jon Garvin wrote:

John Kopanas 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 Susser for showing me how to do self
referential :throughs a while back via his blog.

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 :spank**ers**  , :through => :spanks_as_spankee
has_many :spank**ees**, :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 :-).

John Kopanas wrote:

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 :-).

Josh Susser, 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.