2012-08-06 165 views
1

在具有1-> N-> N關聯的場景中。例如:發佈 - >評論 - >投票(投票將是投票評論人的名單)。要顯示一個網頁,查詢包括可能類似於:ActiveRecord - 查詢執行後如何執行?

@post = Post.where(:id => 100).includes({:comments => :votes}).first 

我開始添加緩存支持。這意味着如果部分評論已被緩存,我將不需要一直包含評論/投票。所以我想如果有一種方法可以使代碼看起來像:

# controller 
@post = Post.find(100) 

# view 
<% cache('comments', @post.last_comment_time do %> 
    <% @post.includes({:comments => :votes}).comments.each do |comment| # ???? %> 
<% end %> 

運行「後查詢」包括,該協會將「填滿」。所以@ post.comments將被填充,每個評論將包括所有的投票。有沒有辦法做到這一點?

P.S.我知道該視圖不是運行查詢的最佳位置,這只是一個示例。

回答

2

在最新版本的rails中,所有的finder-methods都會返回一個代理對象,它只會在您發送一些迭代器方法(如allfirst)時觸發數據庫調用。這就是爲什麼你可以鏈接所有的電話,如Post.where.order.sort.bla

儘管加載後期模型並稍後使用includes調用是不可能的。 includes通過對使用模型實例加載的關係使用join調用,以便每個關係只有一個數據庫調用,而不是一個。

在您的視圖中執行active_record代碼也是一個不好的做法。數據檢索是控制器的責任,而不是視圖。

+0

我添加了一個編輯,在視圖的查詢工作只是一個例子。對於1-> N,也包括使用另一個選擇。所以從技術上講,可以向ActiveRecord添加一個函數來執行額外的選擇並填充關聯。不過謝謝你確認這件事尚不存在。 – mbdev 2012-08-06 18:24:10

0

這是一個相當古老的問題,但這個可以可以現在做這樣

# controller 
@post = Post.find(100) 

# view 
<% cache('comments', @post.last_comment_time do %> 
    <% ActiveRecord::Associations::Preloader.new.preload @post, comments: :votes # this will trigger one query %> 
    <% @post.comments.each do |comment| # this will not trigger any additional queries %> 
<% end %> 

不是最乾淨的方式,但它確實