有时说唱歌曲有不止一个艺术家。例如,Nicki Minaj's "Roman's Revenge"以Eminem为特色,因此在Rap Genius catelog中显示为“Nicki Minaj(Ft.Eminem) - 罗马的复仇”。
在Rap Genius上,我通过具有以下属性的performances
连接模型为特色艺术家建模:
song_id
artist_id
role
(“主要”或“特色”)所以:
在artist.rb
:
has_many :songs, :through => :performances
在song.rb
:
has_many :artists, :through => :performances
在song.rb
:
def primary_artists
performances.select{|p| p.role == 'primary'}.map(&:artist).compact
end
def featured_artists
performances.select{|p| p.role == 'featured'}.map(&:artist).compact
end
# from the user's perspective there's only one primary artist
def primary_artist
primary_artists.first
end
问题是如何实施Song#primary_artist=
和Song#featured_artists=
。现在我正在做这个,这是错误的:
def primary_artist=(artist)
return if artist.blank?
Performance.song_id_eq(id).role_eq('primary').destroy_all
performances.build(:artist => artist, :role => 'primary')
end
这个错误的原因是这种方法会在现场销毁所有现有的主要艺术家,但只有在保存歌曲时才会创建替换的主要艺术家。因此,如果歌曲保存失败,它的主要艺术家将被删除。
这样做的正确方法是什么?我们希望只有在歌曲保存成功时才能删除旧的主要艺术家,所以一个想法是:
def primary_artist=(artist)
return if artist.blank?
#Performance.song_id_eq(id).role_eq('primary').destroy_all
@performances_to_destroy << Performance.song_id_eq(id).role_eq('primary')
performances.build(:artist => artist, :role => 'primary')
end
def after_save
@performances_to_destroy.each(&:destroy)
end
但这似乎仍然有点令人困惑/ hackish。
答案 0 :(得分:0)
略有不同的想法,但在这里艺术家和歌曲之间有两种关系,即一首歌与艺术家的关系如下:
,这不会有点简单和清晰。belongs_to :primary_artist, :class_name => "Artist"
has_and_belongs_to_many :featured_artists, :class_name => "Artist"