2013-05-01 70 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