views:

78

answers:

2

Sometimes more than one artist will be on a song. For example, Jay-z's new song "A Star is Born" features the artist Cole, and thus would be listed as "Jay-z (featuring Cole) - A Star is Born" in a catalog. My question is how to model this in my database.

Right now it's pretty simple: every song belongs_to :artist and every artist has_many :songs. I want to change this so that songs have many artists, with one artist specified as "primary" -- i.e., if A, B, and C are all associated with a given song and A is primary, the artist of that song will be displayed as "A (featuring B and C)".

Here's what I'm thinking:

Song:

has_many :artists, :through => :performances

Artist:

has_many :songs, :through => :performances

where the performance model would have a single field for primary?, designating whether a given performance was the "primary" performance on the song, meaning that the artist associated with that performance is the primary artist on the song.

Does this approach make sense?

+2  A: 

Yes. You nailed it.

Fragsworth
A: 

It looks like you're using performances as an join table with added information to link songs to artists. But this does not work well enough. Songs can have many performances, and each performance can have multiple performers.

I would restructure the database to use a the following structure. Unfortunately it would require a little more work to add a Song to the database, but allows for covers, multiple versions of the song, and duets.

Song (Attributes: Title)

  • has many Performances
  • has many Performers (through Performances)
  • has many Artists (through Performers)

Performance (Foreign Key: Song_id, Attributes: Date, Year, Length, Genre, Album, )

  • belongs to Song
  • has many Performers
  • has many Artist (through Performers)

Performers (Foreign keys: Performance_id, Artist_id, Attributes: Role)

  • has one Song (through Performers) N.B. has_one :through is not a core feature of Rails
  • belongs to Performances
  • belongs to Artist

Artist (Attributes: Name, Date of Birth, etc. (other Personal inforamtion))

  • has many Performers
  • has many Performances (through Performers)
  • has many Songs (through Performances)

If you wanted to enforce 1 primary artist/performance it would be done as validation in Performers.

class Performers < ActiveRecord::Base
  validates_uniqueness_of :role, :scope => [:performance_id], :if => Proc.new{|performer| performer.role == "primary"}
end
EmFi