Forum: Ruby on Rails :through alternate

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
084e60021b5d9e11b475876ea40c1263?d=identicon&s=25 Thomas Counsell (tamc)
on 2006-03-30 01:49
I'd like to use :through to create a web of associations like:

class Thing < ActiveRecord::Base
  has_many :child_things, :through => :thing_thing
  has_many :parent_things, :through => :thing_thing, :some_other_option?
end

class ThingThing < ActiveRecord::Base
  belongs_to :thing
  belongs_to :child_thing, :class_name => 'Thing', :foreign_key =>
'child_thing_id'
end

The child_things works. The parent_things does not, or at least, I
cannot figure out the sytnax. I would like it to issue an sql like:

SELECT things.* FROM things INNER JOIN thing_things ON things.id =
thing_things.thing_id WHERE (thing_things.child_thing_id = 6201)

Is there a way to trigger this sql using the through options?

Many thanks

Tom
9f0f89bbd9e1ecfbaab6584e429b7a2f?d=identicon&s=25 Josh Susser (jsusser)
on 2006-03-30 02:36
It looks like you are trying to create a self-referential has_many
:through association, which should work just fine for what you want.
However you don't have it set up properly. The :through option on a
has_many association must refer to another has_many association in the
same model. It gets to its target through the other association, thus
the name.

Here's an example snipped from the Rails 1.1 test code (always a good
place to look for example code):

class Author < ActiveRecord::Base
  has_many :author_favorites
  has_many :favorite_authors, :through => :author_favorites, :order =>
'name'
end

class AuthorFavorite < ActiveRecord::Base
  belongs_to :author
  belongs_to :favorite_author, :class_name => "Author", :foreign_key =>
'favorite_author_id'
end

If you need to change the name of the association from its name in the
join model, use the :source option to specify that name. Check the docs
on that.

I should blog an article on this soon, as it can get a bit tricky to
combine all the options and get them to work together correctly.

--
Josh Susser
http://blog.hasmanythrough.com



Thomas Counsell wrote:
> I'd like to use :through to create a web of associations like:
>
> class Thing < ActiveRecord::Base
>   has_many :child_things, :through => :thing_thing
>   has_many :parent_things, :through => :thing_thing, :some_other_option?
> end
>
> class ThingThing < ActiveRecord::Base
>   belongs_to :thing
>   belongs_to :child_thing, :class_name => 'Thing', :foreign_key =>
> 'child_thing_id'
> end
>
> The child_things works. The parent_things does not, or at least, I
> cannot figure out the sytnax. I would like it to issue an sql like:
>
> SELECT things.* FROM things INNER JOIN thing_things ON things.id =
> thing_things.thing_id WHERE (thing_things.child_thing_id = 6201)
>
> Is there a way to trigger this sql using the through options?
>
> Many thanks
>
> Tom
084e60021b5d9e11b475876ea40c1263?d=identicon&s=25 Thomas Counsell (tamc)
on 2006-03-30 09:22
Thanks Josh.

I didn't explain myself clearly.  In terms of your model, I'm really
looking for the ability to add a reverse link:

class Author < ActiveRecord::Base
   has_many :author_favorites
   has_many :favorite_authors, :through => :author_favorites, :order =>
'name'
   # I'd like the reverse as well:
   has_many :other_authors_who_love_me, :through => :author_favourites
end

 class AuthorFavorite < ActiveRecord::Base
   belongs_to :author
   belongs_to :favorite_author, :class_name => "Author", :foreign_key =>
 'favorite_author_id'
 end

The :source option appears to rename the association, what I want is to
have :other_authors_who_love_me return AuthorFavorite#author by joining
on AuthorFavorite#favorite_author.

Is this possible?

Thanks

Tom

Josh Susser wrote:
> It looks like you are trying to create a self-referential has_many
> :through association, which should work just fine for what you want.
> However you don't have it set up properly. The :through option on a
> has_many association must refer to another has_many association in the
> same model. It gets to its target through the other association, thus
> the name.
>
> Here's an example snipped from the Rails 1.1 test code (always a good
> place to look for example code):
>
> class Author < ActiveRecord::Base
>   has_many :author_favorites
>   has_many :favorite_authors, :through => :author_favorites, :order =>
> 'name'
> end
>
> class AuthorFavorite < ActiveRecord::Base
>   belongs_to :author
>   belongs_to :favorite_author, :class_name => "Author", :foreign_key =>
> 'favorite_author_id'
> end
>
> If you need to change the name of the association from its name in the
> join model, use the :source option to specify that name. Check the docs
> on that.
>
> I should blog an article on this soon, as it can get a bit tricky to
> combine all the options and get them to work together correctly.
>
> --
> Josh Susser
> http://blog.hasmanythrough.com
>
>
>
> Thomas Counsell wrote:
>> I'd like to use :through to create a web of associations like:
>>
>> class Thing < ActiveRecord::Base
>>   has_many :child_things, :through => :thing_thing
>>   has_many :parent_things, :through => :thing_thing, :some_other_option?
>> end
>>
>> class ThingThing < ActiveRecord::Base
>>   belongs_to :thing
>>   belongs_to :child_thing, :class_name => 'Thing', :foreign_key =>
>> 'child_thing_id'
>> end
>>
>> The child_things works. The parent_things does not, or at least, I
>> cannot figure out the sytnax. I would like it to issue an sql like:
>>
>> SELECT things.* FROM things INNER JOIN thing_things ON things.id =
>> thing_things.thing_id WHERE (thing_things.child_thing_id = 6201)
>>
>> Is there a way to trigger this sql using the through options?
>>
>> Many thanks
>>
>> Tom
9f0f89bbd9e1ecfbaab6584e429b7a2f?d=identicon&s=25 Josh Susser (jsusser)
on 2006-03-30 17:45
The :source option doesn't just rename the association, but it chooses
which association in the join model to use to join to the target model.
I think it will do just what you want:

   has_many :other_authors_who_love_me, :through => :author_favourites,
        :source => :author

--
Josh Susser
http://blog.hasmanythrough.com


Thomas Counsell wrote:
> Thanks Josh.
>
> I didn't explain myself clearly.  In terms of your model, I'm really
> looking for the ability to add a reverse link:
>
> class Author < ActiveRecord::Base
>    has_many :author_favorites
>    has_many :favorite_authors, :through => :author_favorites, :order =>
> 'name'
>    # I'd like the reverse as well:
>    has_many :other_authors_who_love_me, :through => :author_favourites
> end
>
>  class AuthorFavorite < ActiveRecord::Base
>    belongs_to :author
>    belongs_to :favorite_author, :class_name => "Author", :foreign_key =>
>  'favorite_author_id'
>  end
>
> The :source option appears to rename the association, what I want is to
> have :other_authors_who_love_me return AuthorFavorite#author by joining
> on AuthorFavorite#favorite_author.
>
> Is this possible?
084e60021b5d9e11b475876ea40c1263?d=identicon&s=25 Thomas Counsell (tamc)
on 2006-03-30 20:24
Thanks again Josh, that didn't do what I want.  After much time wasted
the solution was obvious (although a little clunky), so it is probably
me not explaining clearly.

class Author < ActiveRecord::Base
  # Forwards
   has_many :author_favorites
   has_many :favorite_authors, :through => :author_favorites, :order =>
'name'

  # Backwards
  has_many :reverse_author_favourites, :class_name => 'AuthorFavorite',
:foreign_key => :favorite_author
   has_many :other_authors_who_love_me, :through =>
:reverse_author_favourites, :source => :authors
end

 class AuthorFavorite < ActiveRecord::Base
   belongs_to :author
   belongs_to :favorite_author, :class_name => "Author", :foreign_key =>
 'favorite_author_id'
 end


Josh Susser wrote:
> The :source option doesn't just rename the association, but it chooses
> which association in the join model to use to join to the target model.
> I think it will do just what you want:
>
>    has_many :other_authors_who_love_me, :through => :author_favourites,
>         :source => :author
This topic is locked and can not be replied to.