About an hour ago i asked a question on rails associations:
Question on Proper Associations in Rails
The accepted answer from that question got me thinking about relationships more deeply and I’d like to present the SO community with this situation.
My previous question used poet, poem, and printing as the models… For this one let’s use the music industry:
The models are:
- Artist
- Album
- Song
- Genre
The following statements are to be considered true:
- An album can have multiple artists – ie Metallica and Pantera release an xmas album
- A song can belong to multiple albums – ie Yellow Submarine is on the original album as well as a number of “Greatest hits” albums from The Beatles
- An individual song can also have multiple “featured” artists that differ from the album artist – ie Snoop Dogg owns the album but does a song featuring Harry Connick Jr. Or an even better example is when a DJ releases an album where ALL the songs are by other artists.
- Artist, Album, and Song can all be classified under multiple/different Genres – ie Brian Setzer Orchestra is categorized as “Swing”, one of their albums could be “Swing, Rockabilly” and an individual song on that album could be “Jump Blues”.
When digging through this problem, I immediately see that models such as Artist & Genre can be “reused”. We would NOT want to save a artist’s information more than once — so for example in the event we have a song w/ both a main artist and featured artist BOTH artists’ information should live in the DB’s “Artist” table.
Additionally, when reviewing the “featured” artist aspect (statement #2) it seems we have an additional attribute that should be on the association — something like a “featured” flag.
Here is how i think the associations should be setup — and also the apex of my post…. is this right, and how can i make it better?
class Artist < ActiveRecord::Base
has_and_belongs_to_many :albums
has_and_belongs_to_many :genres
has_many :featurings
has_many :features, :through => :featurings, :conditions => "featured = true"
end
class Album < ActiveRecord::Base
has_and_belongs_to_many :artists
has_and_belongs_to_many :songs
has_many :featurings
has_many :featured_artists, :through => :featurings, :conditions => "featured = true"
end
class Song < ActiveRecord::Base
has_and_belongs_to_many :genres
has_many :artists
has_many :featurings
has_many :featured_artists, :through => :featurings, :conditions => "featured = true"
end
class Genre < ActiveRecord::Base
has_and_belongs_to_many :artists
has_and_belongs_to_many :songs
end
class Featurings < ActiveRecord::Base
# the db table for this class should have a "featured" boolean.
belongs_to :artist
belongs_to :album
belongs_to :song
end
As usual, huge thanks to those who take the time to read and give input! it’s much appreciated!
This is more of a discussion than a question, but I’ll attempt to address your concerns. I am not testing any of your code, so these are just my thoughts.
Should you need a separate table for this? The information is already stored through the association between songs and genres. Unless artists can belong to genres despite not having songs in said genres, you should not reproduce this information in another HABTM association.
Vice versa, the opposite association may be redundant:
As for your design of the featuring aspect, it seems that having a feature with the flag featured set to true is also redundant. However, that is because of the naming, so if I were you I’d rename it to Release instead (songs can be released on multiple albums). If you think of the featured flag as existing between the artist and the song, you should add the flag to the enjoining entity (forgot the term for this).
However, since it is expressed as a HABTM association, there is no intervening model. Thus, you will have to convert this to use has_many on both Song and Artist, with the intervening model containing belong_to associations as well as a featured flag. This is actually the Release model.
This (again no testing has been done) cuts down your models to this: