Я не фанат ассоциаций HABTM. Поэтому я использовал ассоциацию has_many. Для обозначения жанра, относящегося к Album, Song и т. Д., Я использовал полиморфные ассоциации Решение довольно сложное. Но он отвечает всем требованиям:
class Artist
has_many :genre_links, :as => :genre_holder
has_many :genres, :through => :genre_links
has_many :artist_links
has_many :albums, :through => :artist_links,
:source => :artist_holder, :source_type => "Album"
has_many :songs, :through => :artist_links,
:source => :artist_holder, :source_type => "Song"
has_many :featured_songs, :through => :artist_links,
:source => :artist_holder, :source_type => "Song",
:conditions => {:featured => true}
end
Используйте параметр :source_type
для создания ассоциаций для альбомов и песен.
class Genre
has_many :genre_links
has_many :albums, :through => :genre_links,
:source => :genre_holder, :source_type => "Album"
has_many :songs, :through => :genre_links,
:source => :genre_holder, :source_type => "Song"
end
class GenreLink
belongs_to :genre_holder, :polymorphic => true
belongs_to :genre
end
class ArtistLink
# featured
belongs_to :artist
belongs_to :artist_holder, :polymorphic => true
end
Нам нужен собственный SQL, чтобы получить избранные песни для альбома.
class Album < ActiveRecord::Base
has_many :genre_links, :as => :genre_holder
has_many :genres, :through => :genre_links
has_many :artist_links, :as => :artist_holder,
:condition => {:featured => false}
has_many :artists, :through => :artist_links
has_many :album_songs
has_many :songs, :through => :album_songs
has_many :featured_artists, :class => "Artist", :custom_sql => '
SELECT A.* FROM artists A WHERE A.id IN (
SELECT DISTINCT B.artist_id FROM artist_links B
WHERE B.artist_holder_type = "Song" AND B.featured = 1 AND
B.artist_holder_id IN (#{song_ids.join(",")}))'
end
Теперь к остальным классам:
class AlbumSong
belongs_to :album
belongs_to :song
end
class Song < ActiveRecord::Base
has_many :genre_links, :as => :genre_holder
has_many :genres, :through => :genre_links
has_many :album_songs
has_many :albums, :through => :album_songs
has_many :artist_links, :as => :artist_holder,
:condition => {:featured => :false}
has_many :artists, :through => :artist_links
has_many :featured_artist_links, :class => "ArtistLink",
:as => :artist_holder, :condition => {:featured => :true }
has_many :featured_artists, :through => :featured_artist_links,
:source => :artist
end
Исполнитель может быть связан с альбомом и / или песней.
album1.artists << artist1
song1.artists << artist1
Пометка песни как избранной:
Рельсы 3
song1.featured_artists << artist2
Rails автоматически устанавливает параметры условия хеширования ассоциации при создании. Так что больше нечего делать.
Рельсы 2.x
song1.featured_artist_links.create(:featured => true, :artist => artist2)