Forum: Ruby on Rails Viewing object associated via "has_many :through"?

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.
6ca489fc849bf3ccb2df736e73d0a06e?d=identicon&s=25 Christian Braun (christianb)
on 2007-02-05 19:05
This is my first question to the Forum. I’ve set up these associations:

class Playlist < ActiveRecord::Base
  …
  has_many :playlists_tracks, :dependent => :destroy
  has_many :track_ones, :through => :playlists_tracks, :source => :track
  has_many :track_twos, :through => :playlists_tracks, :source => :track
end

class Track < ActiveRecord::Base
  …
  has_many :playlists_tracks, :dependent => :destroy
  has_many :playlists, :through => :playlists_tracks
  has_many :playlists, :through => :playlists_tracks
end

class PlaylistsTrack < ActiveRecord::Base
  belongs_to :playlist
  belongs_to :track_one, :class_name => :track, :foreign_key =>
'track_one_id'
  belongs_to :track_two, :class_name => :track, :foreign_key =>
'track_two_id'
end

With them I’m able to save to the playlists_tracks table the following:
id, playlist_id, track_one_id, track_two_id. That all seems to work
fine.

But no matter what I put in my playlists/show view file, I get an error
message when I attempt to view the tracks associated with a playlist.
For example:

<% for track in @playlist.tracks %>

<tr>
<td><%= playlist.track_one.title %></td>
</tr>

<% end %>

gets me this:

undefined method `tracks' for #<Playlist:0xeb4a380>

I think the problem revolves around the "class_name" and "source"
options, as I have no problem displaying the name of the Playlistcreator
(who is also associated with Playlist through a "has many :through"
association, but without the “class_name” and “source” options) via the
playlists/show view.

Where am I going wrong? What do I need to do to fix this?
456f5e099eb136439d751598e32d8607?d=identicon&s=25 Bill Siggelkow (Guest)
on 2007-02-05 20:53
(Received via mailing list)
You want to use @playlists.playlists_tracks in your view ...

On Feb 5, 1:05 pm, Christian Braun <rails-mailing-l...@andreas-s.net>
6ca489fc849bf3ccb2df736e73d0a06e?d=identicon&s=25 Christian Braun (christianb)
on 2007-02-05 21:26
Bill Siggelkow wrote:
> You want to use @playlists.playlists_tracks in your view ...

Thank you Bill!

That has got me a step further. This in the view, for example:

<% for track_one in @playlist.playlists_tracks %>

<tr>
<td><%= track_one.id %></td>
</tr>

<% end %>

now displays the track_one.id, which is a good sign.

But I still can't reach beyond the playlists_tracks join table to pull
the title of the track from the tracks table itself. I need the "title"
of the track where the "track.id" is the same as the "track_one.id". I
think I need a trick to kind of weave through the ":source" and
":class_name" options to get to the tracks table, but maybe I'm missing
something obvious here. Any ideas?

Again, many thanks for your answer.
456f5e099eb136439d751598e32d8607?d=identicon&s=25 Bill Siggelkow (Guest)
on 2007-02-05 22:10
(Received via mailing list)
I think what you need to do is leverage your has_many :through
relationship. Something like:

<% for track in @playlist.track_ones %>
  <tr>
  <td><%= track.title %></td>
 </tr>
<% end %>

or more idiomatically

<% @playlist.track_ones.each do |track| %>
  <tr>
  <td><%= track.title %></td>
 </tr>
<% end %>

I don't know your data model, however, the "track_ones" thing kind of
smells a bit of an incorrect data model. In general, if you have a
table
that enumerates a set of columns (track_1, track_2, ...) it may
indicate that you are not modeling a parent -> child relationship. It
was just a thought ... I am probably barking up the wrong tree ...


On Feb 5, 3:26 pm, Christian Braun <rails-mailing-l...@andreas-s.net>
6ca489fc849bf3ccb2df736e73d0a06e?d=identicon&s=25 Christian Braun (christianb)
on 2007-02-05 22:55
Bill Siggelkow wrote:

> I think what you need to do is leverage your has_many :through
> relationship. Something like:
>
> <% for track in @playlist.track_ones %>
>   <tr>
>   <td><%= track.title %></td>
>  </tr>
> <% end %>

Thanks again. I'd already tried that and got this error message:

Could not find the source association(s) :track in model PlaylistsTrack.
Try 'has_many :track_ones, :through => :playlists_tracks, :source =>
<name>'.  Is it one of :track_two, :playlist, or :track_one?

I've been through all the different variants I can think of (like the
odd one in my original example), but they all throw up an error message.
I tried acting on the error message I just listed, but didn't get
anywhere with it. Can you or anyone see any wisdom in it that'll help
me?

> I don't know your data model, however, the "track_ones" thing kind of
> smells a bit of an incorrect data model.

Bad choice of name, I agree. It just refers to which position in the
form the track was selected at, and that's arbitrary, non-essential
information. I'll have a think about that, though, as people don't tend
to give their kids ordinals as names, and you may be right. But even if
my model is a bit skewed, I think I'd be having the same problem with
"jazz_tracks" and "rock_tracks", etc.

Can you or anyone else think what the problem might be? I'm pretty sure
it relates to the ":source" and ":class_name" options. Again, I have no
problem saving all the relevant data to the playlists_tracks join table,
but then can't access the tracks table afterward to grab the track name.
456f5e099eb136439d751598e32d8607?d=identicon&s=25 Bill Siggelkow (Guest)
on 2007-02-06 18:33
(Received via mailing list)
I believe that Rails uses the :source to identify the foreign key in
the join table for the :through relationship. Try this ...

class Playlist < ActiveRecord::Base
  ...
  has_many :playlists_tracks, :dependent => :destroy
  has_many :track_ones, :through => :playlists_tracks, :source
=> :track_one
  has_many :track_twos, :through => :playlists_tracks, :source
=> :track_two
end

Then use the your :through relationships in the view as before ..


On Feb 5, 4:55 pm, Christian Braun <rails-mailing-l...@andreas-s.net>
6ca489fc849bf3ccb2df736e73d0a06e?d=identicon&s=25 Christian Braun (christianb)
on 2007-02-06 19:03
(Received via mailing list)
Yes, you're right!

With this model (like you said):

class Playlist < ActiveRecord::Base
  ...
  has_many :playlists_tracks, :dependent => :destroy
  has_many :track_ones, :through => :playlists_tracks, :source
=> :track_one
  has_many :track_twos, :through => :playlists_tracks, :source
=> :track_two
end

And this in the playlists/show view:

<% for track_one in @playlist.track_ones %>

<tr>
<td><%= track_one.title %></td>
</tr>

<% end %>

I can display the track's name.

Bill, Thank you so much! I really appreciate your walking me and my
noobishness through this. I can now link the last pieces of my
application together, and that's a great relief. Cheers!
This topic is locked and can not be replied to.