Reputation: 14434
Based on the following I'd like to query albums based on an artist
and their artist_credit
. The artist_credit
association is polymorphic and can belong to a release or track. This prevents me doing a HMT. I can grab albums from the track side by doing an includes in my query as so:
Album.includes(tracks: :artist_credits).where(artist_credits: { id: artist_id })
But what I'd like to do is get ahold of both tracks AND releases. I thought of using an or
clause but get this error:
ArgumentError (Relation passed to #or must be structurally compatible. Incompatible values: [:includes])
When attempting this:
Album.includes([tracks: :artist_credits, releases: :artist_credits]).where(artist_credits: { id: artist_id }).or(where(artist_credits: { id: artist_id }))
How can I get this to work? Any better way to do this?
class Album < ApplicationRecord
has_many :releases, dependent: :destroy
has_many :tracks, dependent: :destroy
has_many :album_artists, dependent: :destroy
has_many :artists, through: :album_artists
end
class Track < ApplicationRecord
has_many :artist_credits, as: :creditable, dependent: :destroy
belongs_to :album
end
class Release < ApplicationRecord
has_many :artist_credits, as: :creditable, dependent: :destroy
belongs_to :album
end
class ArtistCredit < ApplicationRecord
belongs_to :artist
belongs_to :creditable, polymorphic: true # release or track
end
Upvotes: 0
Views: 44
Reputation: 29318
I would recommend the following
class Album < ApplicationRecord
scope :accredited_artist, ->(artist_id) {
includes([tracks: :artist_credits, releases: :artist_credits])
.where(id:
where(
id: Track.accredited_artist(artist_id).select(:album_id)
).or(
where(
id: Release.accredited_artist(artist_id).select(:album_id)
)
)
)
}
end
class Track < ApplicationRecord
scope :accredited_artist, ->(artist_id) {
joins(:artist_credits).where(artist_credits: { id: artist_id })
}
end
class Release < ApplicationRecord
scope :accredited_artist, ->(artist_id) {
joins(:artist_credits).where(artist_credits: { id: artist_id })
}
end
In theory this should result in a query that looks akin to
SELECT
albums.*
FROM
albums
WHERE
albums.id IN (
SELECT
albums.id
FROM
albums
WHERE
albums.id IN (
SELECT
tracks.album_id
FROM
tracks
INNER JOIN artist_credits ON [whatever your join is here]
WHERE
artist_credits.artist_id = [ID]) OR
albums.id IN (
SELECT
releases.album_id
FROM
releases
INNER JOIN artist_credits ON [whatever your join is here]
WHERE
artist_credits.artist_id = [ID])
)
Upvotes: 1