[UPDATE, Scroll down for solution]
I am busy developing a music streaming application with Rails and am stuck on a basic problem. I am not sure how to call my joint table.
This is my flow:
I have 3 tables that relate to playlists and tracks
create_table "tracks", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "artist"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "album_id", null: false
t.bigint "user_id", null: false
t.string "photo"
t.string "track"
t.index ["album_id"], name: "index_tracks_on_album_id"
t.index ["user_id"], name: "index_tracks_on_user_id"
end
create_table "playlists", force: :cascade do |t|
t.string "playlist_title"
t.text "playlist_description"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "user_id", null: false
t.index ["user_id"], name: "index_playlists_on_user_id"
end
create_table "playlists_tracks", id: false, force: :cascade do |t|
t.bigint "playlist_id", null: false
t.bigint "track_id", null: false
end
Desired outcome -> Render tracks in Show.html.erb where tracks have a playlist_id of x
My current code looks like this in my playlists_controller.rb
def show
@playlist = Playlist.find(params[:id])
@track = Track.where(playlist_id: params[:id])
end
the result is an error saying
column tracks.playlist_id does not exist
LINE 1: SELECT "tracks".* FROM "tracks" WHERE "tracks"."playlist_id"...
If i go to my tracks table in schema, it makes sense that it cannot find a playlist_id value because the table doesn't have a playlist_id column.
However, there is a playlist_id in my playlists_tracks joint table along with a track_id.
What I don't understand >>
When a user adds a track, I know the track info is being added to the tracks table. But there is no info that is added to playlists_tracks table. I am expecting that when a user adds a track to a playlist, this is when an existing track will be associated to a/many playlist(s). I have not yet created the function that will add a track to the playlist.
Right now I am merely trying view the SHOW page of a specific playlist which contains code that will render the related tracks. My current code does not find the playlist_id in tracks table because it does not exist. My first thought is to change my SHOW method so that it searches the playlists_tracks table instead of the tracks table.
However, my syntax does not make sense. do I call my playlists_tracks table like below? With a capital P and singular track?
New show method:
def show
@playlist = Playlist.find(params[:id])
@playlist_track = Playlists_track.where(playlist_id: params[:id])
end
Hope the size of my description helps and is not an overkill! Thanks for your time.
For further reference, here are my associated models
class Playlist < ApplicationRecord
has_many :tracks, through: :playlists_tracks
has_many :tags, through: :playlists_tags
belongs_to :user
validates :playlist_title, presence: true, length: { in: 1..20 }
validates :playlist_description, presence: true, length: { in: 10..60 }
has_one_attached :photo
end
class Track < ApplicationRecord
belongs_to :album
belongs_to :user
has_many :playlists, through: :playlists_tracks
has_many :tags, through: :tags_tracks
validates :title, presence: true, length: { in: 1..20 }
validates :description, presence: true, length: { in: 10..60 }
has_one_attached :photo
has_one_attached :track
end
[UPDATE]
new model
class PlaylistTrack < ApplicationRecord
belongs_to :track
belongs_to :playlist
end
Addition to Schema
create_table "playlist_tracks", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "playlist_id", null: false
t.bigint "track_id", null: false
t.index ["playlist_id"], name: "index_playlist_tracks_on_playlist_id"
t.index ["track_id"], name: "index_playlist_tracks_on_track_id"
end
corrected Playlist Model
class Playlist < ApplicationRecord
has_many :playlist_tracks
has_many :tracks, through: :playlist_tracks
has_many :tags, through: :playlist_tags
belongs_to :user
validates :playlist_title, presence: true, length: { in: 1..20 }
validates :playlist_description, presence: true, length: { in: 10..60 }
has_one_attached :photo
end
Corrected Track Model
class Track < ApplicationRecord
belongs_to :album
belongs_to :user
has_many :playlist_tracks
has_many :playlists, through: :playlist_tracks
has_many :tags, through: :tags_tracks
validates :title, presence: true, length: { in: 1..20 }
validates :description, presence: true, length: { in: 10..60 }
has_one_attached :photo
has_one_attached :track
end
Corrected Show Method
def show
@playlist = Playlist.find(params[:id])
@tracks = @playlist.tracks
end
Join tables with N:N relationships are so confusing. I am anticipating further errors as my tests in console are not promising(seeding a playlist with a track) but at least the Playlist Show Page is now rendering.
Hope this helps and if you have any pointers, please leave them below :)
Creating as answer to include code snippets:
I'm going to assume that the "playlist_tracks" table was created with foreign keys
/references
to the relevant tables it is joined to:
class CreatePlaylistTracks < ActiveRecord::Migration[6.0]
def change
create_table :playlist_tracks do |t|
t.references :playlist, null: false, foreign_key: true
t.references :track, null: false, foreign_key: true
t.timestamps
end
end
end
you'll need to tweak your model (also assuming that you have a PlaylistTrack
model defined, with belongs_to
s in it):
class Playlist < ApplicationRecord
has_many :playlist_tracks, inverse_of: :playlist
has_many :tracks, through: :playlist_tracks
has_many :tags, through: :playlist_tags
belongs_to :user
validates :playlist_title, presence: true, length: { in: 1..20 }
validates :playlist_description, presence: true, length: { in: 10..60 }
has_one_attached :photo
end
then in the controller, you should just be able to do:
def show
@playlist = Playlist.find(params[:id])
@track = @playlist.tracks
end
can you see if that makes a difference?