Иногда рэп-песни имеют более одного исполнителя.Например, «Месть Романа» Ники Минажа содержит Эминема и, таким образом, появляется в качестве «Мести Романа» (Месть Романа) в каталогов Rap Genius .
В Rap Genius I модель представлена художниками через performances
модель соединения, которая имеет следующие атрибуты:
song_id
artist_id
role
(«основной» или «рекомендуемый»)
Итак:
In 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
Но это все равно кажется немного запутанным / хакерским.