2013-03-20 51 views
7

我渴望加載與其關聯的模型對象:Rails的預先​​加載和where子句

user= User.includes(:posts).find(1) 

但隨後在代碼中的某些點我願做這樣的事情:

user.posts.where(:topic => "x") 

但是,只是再次運行查詢。所以相反,我想我會這樣做:

user.posts.select{|post| post.topic == "x" } 

這不會重新運行查詢。但我有幾個問題。

首先,這是正確的做法嗎?

其次,我對這種情況下select做了些什麼感到困惑。因爲當我運行最後一行時,即使我沒有使用includes函數,它第一次運行查詢,然後如果我再次運行它,它不......所以有某種緩存涉及? 因爲當我使用where子句它每次運行查詢。

謝謝。

回答

14

select是Enumerable上的Ruby方法。當您第一次運行

user.posts.select{|post| post.topic == "x" } 

user:posts協會將被從數據庫到內存中加載所有Post實例;具體到一個ActiveRecord集合對象中。然後在此集合上調用select,使用:topic屬性過濾掉集合中的所有Post實例,該屬性不是"x"

第二次運行上述行不會再次查詢數據庫,因爲您已經將posts加載到內存中。


當你做一個includes像下面

user= User.includes(:posts).find(1) 

它要在:posts關係每個User實例返回渴望負荷(在這種情況下,單個User其中:id1)。您現在已經將所有Post實例加載到內存中,如上一節中所述。

如果你再這樣做

user.posts.where(:topic => "x") 

現在你告訴軌對Post運行查詢,這次發現的所有Post實例,其中:topic"x"並在:user_id也是該:iduserwhere不能像內存中的ARel集合中的「過濾器」一樣工作。


  • 如果你想避免另一個查詢壞,select是過濾在內存中的結果集的好方法。
  • 您可以運行基準測試來發現這是更快:
    1. 查詢數據庫和重新建另一個AREL收集到內存
    2. 遍歷內存enumberable和使用Ruby
  • 運行的過濾器如果你從來沒有需要所有相關:postsuser,你可以很容易地包括在這個原始查詢

    user.includes(:posts).where("posts.topic = ?", 'x') 
    
+0

這是完美的,謝謝! – user1069624 2013-03-20 14:34:33