2014-12-10 52 views
3

使用Rails 4.1.6和Ruby 2.1.2並給予下述的三個對象:導軌當使用4保持連接物體起的順序包括:在通過的has_many關聯

class FilmCollection 
    has_many :film_collection_films, -> { order(:position) } 
    has_many :films, through: :film_collection_films 
end 

class FilmCollectionFilm 
    belongs_to :film_collection_film 
    belongs_to :film 
end 

class Film 
    has_many :film_collection_films 
end 

FilmCollections是膜的集合,其成員通過連接對象FilmCollectionFilm表示。 FilmCollectionFilm有一個位置列,以便集合中的給定成員可以重新排序(像電影隊列一樣),因此我們爲什麼需要連接對象而不是has_and_belongs_to_many。

當我試圖一次加載多個集合的電影時,出現了我的問題。

調用FilmCollection.first.films會得到我的查詢,看起來像:

SELECT `film_collections`.* FROM `film_collections` 
    ORDER BY `film_collections`.`id` ASC LIMIT 1 
SELECT `films`.* FROM `films` 
    INNER JOIN `film_collection_films` ON `films`.`id` = `film_collection_films`.`film_id` 
    WHERE `film_collection_films`.`extensional_film_collection_id` = 1 
    ORDER BY `film_collection_films`.`position` ASC 

哪些訂單的基礎上正確的加入對象位置的電影。

但不是調用FilmCollection.includes(:電影).first.films會讓我下面的查詢:

SELECT `film_collections`.* FROM `film_collections` 
    ORDER BY `film_collections`.`id` ASC LIMIT 1 
SELECT `film_collection_films`.* FROM `film_collection_films` 
    WHERE `film_collection_films`.`film_collection_id` IN (1) 
    ORDER BY `film_collection_films`.`position` ASC 
SELECT `films`.* FROM `films` WHERE `films`.`id` IN (1, 16, 53, 185) 

採集到的正確的電影,但無視在查詢的第二部分的順序。如何在使用.includes()進行加載時仍然保持對連接對象的排序,但仍然沒有n + 1查詢?

+0

嘗試使用'joins'來代替:'FilmCollection.joins(:films).first.films'? – Surya 2014-12-11 07:48:27

+0

我確實找到了即將發佈的解決方案。這可能會起作用,但我認爲加入總體上比總體速度要慢,特別是對於大型表格。雖然我可能是錯的。 – BitPuncher 2014-12-12 01:08:38

+0

注意:在我看來,這是一個只能在Rails 5中修復的bug:/ https://github.com/rails/rails/pull/18766 – 2017-04-04 16:11:39

回答

2

事實證明,您可以通過明確包含連接對象以及通過它的關聯來解決此問題。下面一行將正確選擇所有內容,並保留連接對象上的所有條件/順序。

FilmCollection.includes(film_collection_films: :film) 

如果你做到這FilmCollection.includes(:films)那麼它會選擇FilmCollectionFilms無論如何,然後就折騰他們。所以,上面的代碼會做相同數量的工作,但正確地構建查詢。

+1

也適用於rails 3.2。我還想指出,'FilmCollection.includes(film_collection_films :: film)'和'FilmCollection.includes(:films)'的sql查詢本身是**完全相同的**(使用.to_sql進行測試)。因此,我的教育猜測是如何保存順序(而不是挖掘activerecord代碼)是在執行查詢和構建數組之後,通過ruby的** sort **方法。這可能會導致性能下降,具體取決於記錄總數。儘管我的需求,這是完美的! – mkralla11 2015-01-20 20:46:35