Reputation: 14424
I was interested in creating a model that could stand alone but could also belong to another model. So for example: I have an Artist
that has many Albums
. In addition to having many tracks (which is irrelevant for this case) it also can have many Singles
. Here's the catch. There are some instances where a single doesn't belong to an album and is just used for promo (aka a promo single). So I thought I'd approach it using a polymorphic association:
class Artist < ActiveRecord::Base
has_many :albums
has_many :singles, as: :singleable
end
class Album < ActiveRecord::Base
belongs_to :artist
has_many :singles, as: :singleable
end
class Single < ActiveRecord::Base
belongs_to :singleable, polymorphic: true
end
Not being entirely familiar with polymorphic associations I didn't know if this would be the correct way to setup what I had in mind of doing. Alternatively should I have created an entirely separate model called PromoSingle
or create a dropdown that would define the single type?
Upvotes: 0
Views: 729
Reputation: 9485
I don't think this case actually needs a polymorphic association. It should work, yes, but you'll soon find yourself in situations when you need to perform complicated searches to get seemingly simple results.
Polymorphic association should be used when association is semantically the same, but may involve different objects. It's not the case here, an artist is the one who created the track. But the album isn't.
This can cause trouble at least if you ever decide to fetch specific artist's tracks. Here's what ActiveRecord would have to do with your structure (including internal operations):
album_id
s, whose artist_id
is X (a parameter) singleable_type
is "Album"
and singleable_id
is in the array of albums A, fetched before.singleable_type
is "Artist"
and singleable_id
is X.Here is what I suggest you do.
class Artist < ActiveRecord::Base
has_many :albums
has_many :singles
end
class Album < ActiveRecord::Base
belongs_to :artist
has_many :singles
end
class Single < ActiveRecord::Base
belongs_to :artist
belongs_to :album
end
PromoSingle
s fit well here too. Just because association is defined doesn't mean it should be present: it only means "it might be present, there is a place where we can put it".
Should you absolutely need it to be present (not here, somewhere else), you'd use a validation to ensure.
Otherwise, you may have items that don't belong to anyone, or, technically, belong to nil
(Ruby level) or NULL
(DB level). It's not bad if it makes sense.
Upvotes: 1