2013-07-06 89 views
1

我一直在尋找最好的方法來完成相當一段時間的平庸結果,所以我決定在這裏問一下。在Rails中獲取最後一條相關記錄

的情況如下:我有三個型號,任務,用戶和評論,基本上是這樣的:

class Task < ActiveRecord::Base 
    belongs_to :user 
    has_many :comments 
end 

class Comment < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :task 
end 

class User < ActiveRecord::Base 
    has_many :tasks 
    has_many :comments 
end 

我試圖輸出任務的清單(假設最後10這個問題的目的),以及相關的最後評論爲每個任務和它的作者(用戶模型)與最少查詢可能

謝謝

UPDATE

class Task < ActiveRecord::Base 
    belongs_to :user 
    has_many :comments 
    has_one :last_comment, -> { order 'created_at' }, class_name: "Comment" 
end 

,然後取這樣的評論:

tasks = Task.joins(last_comment: :user) 
    .includes(last_comment: :user) 
    .order('tasks.created_at DESC').limit(10).load 
因此該解決方案是這樣的,我結合由Blue史密斯和harigopal解決方案

其中產生只有一個查詢,這正是我是looki ng for!謝謝!

+0

我不認爲我的理解正確,所以我發佈了有關此評論的進一步解釋:這不是我關心的任務限制,數字完全不相關,我試圖以某種方式來模擬場景,其中任務只有**一條評論**所以問題是如何**加載最後一條相關評論** –

回答

2

您必須加入表格,並且儘量減少數據以儘量減少查詢次數。

例如:

tasks = Task.joins(comments: :user) 
    .includes(comments: :user) 
    .order('tasks.created_at DESC') 
    .limit(10).load 

comments = tasks.first.comments # No query, eager-loaded 
user = comments.first.user  # No query, eager-loaded 

這應該查詢的數量減少到只是一個(非常複雜的一個),所以你必須確保你的索引是及格! :-D

有關合並的官方文檔加入,包括是模糊的,但應該有所幫助:http://guides.rubyonrails.org/active_record_querying.html#joining-multiple-associations

編輯:

這裏有一個演示應用程序使用相同的模型作爲你的使用進行急於加載以上方法。它使用兩個查詢加載數據。啓動應用程序以查看它的行動。

https://github.com/harigopal/activerecord-join-eager-loading

+0

這會產生:PG ::錯誤:錯誤:缺少表「任務」的FROM子句條目 –

+0

我已經使用演示應用程序(SQLite3)更新瞭解決方案。試試看。 –

+0

也許我錯了某處,但是當我嘗試類似的東西時,我有一個左外連接進行評論,並且它加載了所有評論,而不僅僅是10個,所以如果你有10個任務並且每個評論有10,000個,麻煩 – JustMichael

1

你可以嘗試沿着這個線的東西:

class Task 
    scope :recent, order('created_at desc') 
    scope :last, lambda{|n| limit: n } 
end 

現在你有可重複使用的範圍:

Task.recent.last(10) 

而且我猜你要輸出的最後10個任務給定用戶(假設當前登錄的用戶)。

current_user.tasks.recent.last(10).includes(comments: user) 
+0

不要將'scope'與帶參數的lambdas一起使用。改用類方法。 – Hauleth

+0

爲什麼?你可以解釋嗎? –

+0

因爲[優先方式](http://guides.rubyonrails.org/active_record_querying.html#passing-in-arguments)是使用類方法。 – Hauleth

1

你可以試試這個:

class Task < ActiveRecord::Base 
    belongs_to :user 
    has_many :comments 
    has_one :last_comment, :class_name => 'Comment', :order => 'comments.created_at DESC' 
end 

@tasks = Task.limit(10).includes(:last_comment => :user) 

last_comment是一個 「虛擬」 的關聯,只是只加載一個Comment記錄。這種方法的優點是它將使用更少的內存(因爲只需加​​載一個Comment和一個相關的User)。如果你使用includes(comments: user)它可能會消耗大量的內存(如果有很多評論:)。

相關問題