2013-05-01 57 views
0

我正在爲我的Rails應用程序做出非常基本的分析功能。我想提供統計數據,告訴用戶有多少訪問者查看了他們的個人資料,然後根據每個訪問者的具體角色(我在我的應用中使用「rolify」)將其分解。如何減少類似查詢的數量

在用戶控制器的表演動作,我這樣做

@profileviews = Profileview.where(:user_id => @user.id) 
@profileviewsbysomerole = Profileview.where({:user_id => @user.id, :viewer_role => 'someRole'}) 
@profileviewsbysomeotherrole = Profileview.where({:user_id => @user.id, :viewer_role => 'someOtherRole'}) 

,然後在表演的動作,我會做

Your profile has been viewed <%= @profileviews.size %> times. 
Your profile has been viewed by users with a particular role <%= @profileviewsbysomerole.size %> times. 
Your profile has been viewed by users with some other role <%= @profileviewsbysomeotherrole.size %> times. 

有沒有辦法來完成我」 m試圖不做三個單獨的查詢,或者這是獲得這些統計數據的最佳方式(不降低性能)。

回答

1

就性能而言,我認爲是可以的。另一種選擇是查詢所有對象,然後在內存中過濾,但我認爲這不是一個好主意。最好讓數據庫做到最好。

想到的一件事 - 您可以使用單個查詢和group_by以避免進行第二次和第三次調用,但如果您希望獲得某些彙總數據,則這是相關的。

在編碼風格方面,您可以爲不同的查詢定義範圍並在視圖中使用它們,但這可能是一種矯枉過正。

+0

同意,我會定義這些查詢一些範圍,但我不會從視圖中使用它們。它只是使代碼看起來更清潔 – 2013-05-01 21:00:32

+0

感謝您的信息。您介意告訴我group_by如何避免第二次和第三次電話?我明白它是如何被普遍使用的,但我不明白它是如何避免這種呼叫的。 – BrainLikeADullPencil 2013-05-01 21:31:11

+0

例如,如果要計算每個角色的視圖,可以執行以下操作:Profileviews.select(「count(profileviews.id)as num_views,viewer_role as role」)。group(「role」) – davidrac 2013-05-02 04:22:36

1

如果你發現自己使用這些東西放在一起了很多,這可能是不錯的他們捆綁在一起是這樣的:

# in user model 
def profile_view_hash(*roles) 
    views = { 'all' => Profileview.where(:user_id => id).all } 
    roles.each do |role| 
    views.merge!({ 
     role => Profileview.where(:user_id => id, :viewer_role => role).all 
    }) 
    end 
    views 
end 

這應該允許您使用它是這樣的:

# in controller 
@profile_views = @user.profile_view_hash('someRole','someOtherRole') 

# in view 
<%= @profile_views['all'] %> 
<%= @profile_views['someRole'] %> 
<%= @profile_views['someOtherRole'] %> 

順便說一句,在你的例子中,你只顯示.size的輸出。如果這是你所需要的,你應該用count代替all

+0

非常感謝。這很棒。關於你最後的評論,你是否說我應該在我的控制器中這樣做,如果我需要的只是大小(可能在某些情況下,而不是在其他情況下):@profileviewsbysomerole = Profileview.where({:user_id => user。 ID,:viewer_role =>「somerole」})通過在查詢的末尾添加的計算 – BrainLikeADullPencil 2013-05-01 22:32:52

+0

,它防止從導軌計數前檢索所有? – BrainLikeADullPencil 2013-05-01 22:33:31

+0

@BrainLikeADullPencil是的,使用.count會將SQL查詢轉換爲'select count(*)from profile_views',其中yadda yadda..'會更快,但不會有任何數據。 – Unixmonkey 2013-05-02 02:22:47

1

我會離開他們全力以赴的控制器,並作出這樣的觀點:通過移動

Your profile has been viewed <%= @user.profileviews.size %> times. 
Your profile has been viewed by users with a particular role <%= @user.profileviews.select { |profile_view| profile_view.viewer_role == 'someRole' }.size %> times. 
Your profile has been viewed by users with some other role <%= @user.profileviews.select { |profile_view| profile_view.viewer_role == 'someOtherRole' }.size %> times. 

你可以藉此更進一步這個邏輯的Profileview,也許像:

def views_for_role(role) 
    select { |profile_view| profile_view.viewer_role == role }.size 
end 

和委託其在User,也許像:

delegate :views_for_role, :to => :profileview 

這將使你的觀點是這樣的:

Your profile has been viewed <%= @user.profileviews.size %> times. 
Your profile has been viewed by users with a particular role <%= @user.views_for_role 'someRole' %> times. 
Your profile has been viewed by users with some other role <%= @user.views_for_role 'someOtherRole' %> times. 
+0

謝謝你向我展示這一點。我會玩弄它並考慮使用它。 – BrainLikeADullPencil 2013-05-02 17:09:23