假设我在Album
和Song
类之间存在一对多的关系。我想对专辑进行一些复杂的过滤并检索相应的歌曲。
让我们假设一种过滤相册的相当简单的方法
filtered_albums = Album.where('released_on >= ?', from)
.where('rating > ?', rating)
.where(genre: genres)
现在,要检索我目前使用的歌曲
Song.where(album_id: filtered_albums.pluck_id)
产生类似
的查询SELECT *
FROM songs
WHERE album_id IN (1, 5, 34, 92, ..., 2392);
由于需要两个查询(一个用于提取专辑ID,另一个用于获取歌曲),因此效率非常低。
ActiveRecord允许连接表格,例如Songs.joins(:albums)
,但我还没有办法做Songs.joins(filtered_albums)
之类的事情。有没有其他方法可以在没有"拔除"的情况下进行连接。 ids首先?
答案 0 :(得分:1)
您可以使用join
来获得所需的结果。
Song.joins(:album).where('albums.released_on >= ?', from)
.where('albums.rating > ?', rating)
.where(albums: {genre: genres})
joins
方法将关联作为参数。我的意思是,无论你在连接方法中传递什么,都应该是模型中定义的关联名称,否则会引发错误。
修改强>
如果您希望将过滤方法保留在Album
模型本身中,换句话说,您希望在joins
中使用范围。然后你可以这样做
Song.joins(:album).merge(Album.filtered_albums)
此外,您可以将filtered_albums定义为命名范围。因此,请在相册模型中将其定义为:
scope :filtered_albums, ->(from, rating, genres){ where('released_on >= ?', from)
.where('rating > ?', rating).where(albums: {genre: genres}) }
或者定义为类方法。
答案 1 :(得分:1)
您可以这样做:
Song.joins(:albums).where('albums.released_on >= ?', from).where('albums.rating > ?', rating).where('albums.genre = ?', genres)
只进行一次查询。