在include中使用or子句

时间:2019-05-03 13:20:43

标签: ruby-on-rails activerecord

基于以下内容,我想基于artist及其artist_credit查询相册。 artist_credit关联是多态的,可以属于发行版或曲目。这使我无法进行HMT。我可以通过在查询中包含一个内容来从曲目方面抓取专辑:

Album.includes(tracks: :artist_credits).where(artist_credits: { id: artist_id })

但是我想做的是同时掌握两个曲目的版本。我想到要使用or子句,但会收到此错误:

ArgumentError (Relation passed to #or must be structurally compatible. Incompatible values: [:includes])

尝试此操作时:

Album.includes([tracks: :artist_credits, releases: :artist_credits]).where(artist_credits: { id: artist_id }).or(where(artist_credits: { id: artist_id }))

我该如何使用它?还有更好的方法吗?

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

1 个答案:

答案 0 :(得分:1)

我建议以下

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

从理论上讲,这应该导致查询类似于

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])
  )