2014-04-01 39 views
0

假設我在AlbumSong類別之間具有一對多關係。我想對相冊做一些複雜的過濾並檢索相應的歌曲。加入ActiveRecord中的表格和過濾表格

讓我們假設一個相當簡單的方式來篩選專輯

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,另一個提取歌曲),這可能是ver y效率低下。

ActiveRecord允許連接表,例如, Songs.joins(:albums),但我還沒有找到方法來做類似Songs.joins(filtered_albums)的事情。沒有任何其他方式可以在沒有首先「擷取」id的情況下進行連接?

回答

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

或定義爲類方法。

+0

Thanks @Manoj。這工作。我想保留專輯過濾到自己的課堂。請參閱我對上述帖子的評論。 – sakovias

+0

我編輯了我的答案以符合您的要求:) –

+0

您已經度過了我的一天,謝謝!合併方法正是我所期待的:)實際上,它是根據[this]使用最少的ActiveRecord :: Relation方法之一(http://blog.mitchcrowe.com/blog/2012/04/14/ 10-most-underused-activerecord-relation-methods /)post! – sakovias

1

你可以做這樣的事情:

Song.joins(:albums).where('albums.released_on >= ?', from).where('albums.rating > ?', rating).where('albums.genre = ?', genres) 

這讓只有一個查詢。

+0

這工作,謝謝。然而,我的問題是過濾器方法存在於Album類(並且需要很多可選的參數,這裏我沒有指定),並且歌曲查找器位於Song類中。所以它基本上是加入ActiveRecord :: Relation對象(過濾相冊)和歌曲表的問題。也許這是我的應用程序設計的問題。 – sakovias