根据所有者及其父对象验证对象

Validate object based on the owner its parent

我的艺术家和专辑模型之间有一个 has_many through 关联设置。要向此专辑添加 has_many 首曲目。曲目在艺术家(即 特色艺术家 )之间也有 has_many through 关联,其中 Feature 模型用作连接 table.

我想阻止专辑艺术家成为曲目的特色艺术家。例如:

album = Album.find_by(name: "Justified")
track = Album.track.first
artist = Artist.find_by(name: "Justin Timberlake")

track.featured_artists << artist 

# ^^ Should raise error since Justin Timberlake is the album's artist

模型设置

class Album < ActiveRecord::Base
  has_many :album_artists
  has_many :artists, through: :album_artists
end

class Track < ActiveRecord::Base
  belongs_to :album

  has_many :features
  has_many :featured_artists, through: :features, class_name: "Artist", foreign_key: "artist_id"
end

class AlbumArtist < ActiveRecord::Base
  belongs_to :album
  belongs_to :artist

  validates_uniqueness_of :artist_id, scope: :album_id
end

class Feature < ActiveRecord::Base
  belongs_to :track
  belongs_to :featured_artist, class_name: "Artist", foreign_key: "artist_id"
end

class Artist < ActiveRecord::Base
  has_many :album_artists
  has_many :albums, through: :album_artists

  has_many :features
  has_many :tracks, through: :features
end

有没有一种方法可以使用开箱即用的验证方法来完成此操作?如果不是,假设验证器在 Feature 模型中,我将如何创建自定义验证器而不向相册所有者写入长得可笑的查找链?

可以测试两个艺术家数组的交集(&)为空

class Track < ActiveRecord::Base
  belongs_to :album

  has_many :features
  has_many :featured_artists, through: :features, class_name: "Artist", foreign_key: "artist_id"

  validate :featured_artists_cannot_include_album_artists

  def featured_artists_cannot_include_album_artists
    if (album.artists & featured_artists).present?
      errors.add(:featured_artists, "can't include album artists")
    end
  end
end