13

的ActiveRecord协会选择计数包括记录

class User 
    has_many :tickets 
end 

我想创建协会,包含的用户数票的逻辑,并用它在包括(用户HAS_ONE ticket_count)

Users.includes(:tickets_count) 

我试着

has_one :tickets_count, :select => "COUNT(*) as tickets_count,tickets.user_id " ,:class_name => 'Ticket', :group => "tickets.user_id", :readonly => true 

User.includes(:tickets_count) 

ArgumentError: Unknown key: group 

在这种情况下,include中的关联查询应该使用c ount with group by ... 如何使用rails实现这个功能?

更新

  • 我不能改变表结构
  • 我想AR为用户生成的收藏集查询与包括

UPDATE2

我知道SQL我知道如何选择与连接,但我的问题是现在“如何获取数据”。我的问题是关于建立我可以用于包含的关联。由于

UPDATE3 我试图创建关联创建,如用户HAS_ONE ticket_count,但

  1. 看起来像HAS_ONE不支持扩展关联
  2. HAS_ONE不支持:组选项
  3. HAS_ONE不支持finder_sql

回答

12

试试这个:

class User 

    has_one :tickets_count, :class_name => 'Ticket', 
    :select => "user_id, tickets_count", 
    :finder_sql => ' 
     SELECT b.user_id, COUNT(*) tickets_count 
     FROM tickets b 
     WHERE b.user_id = #{id} 
     GROUP BY b.user_id 
    ' 
end 

编辑:

它看起来像has_one协会不支持finder_sql选项。

就可以轻松实现你想要使用的scope/class方法

class User < ActiveRecord::Base 

    def self.include_ticket_counts 
    joins(
    %{ 
     LEFT OUTER JOIN (
     SELECT b.user_id, COUNT(*) tickets_count 
     FROM tickets b 
     GROUP BY b.user_id 
     ) a ON a.user_id = users.id 
    } 
    ).select("users.*, COALESCE(a.tickets_count, 0) AS tickets_count") 
    end  
end 

现在

User.include_ticket_counts.where(:id => [1,2,3]).each do |user| 
    p user.tickets_count 
end 

结合该解决方案会对性能产生影响,如果你有几百万行的tickets表。您应该考虑通过向内部查询提供WHERE来过滤JOIN结果集。

+0

rails 3.2给了我ArgumentError:未知的键:sql – Fivell 2012-02-21 07:39:40

+0

has_one有下一个选项[:class_name,:foreign_key,:select,:conditions,:include,:extend,:readonly,:validate,:remote,:dependent,:counter_cache, :primary_key,:inverse_of,:order,:as,:autosave] – Fivell 2012-02-21 07:41:49

+0

@Fivell,更新了答案。我应该使用'finder_sql'而不是'sql'。我已经更新了我的答案,看看。 – 2012-02-21 08:19:41

8

您可以简单地用于特定用户:

user.tickets.count 

或者如果你想让这个值自动被Rails缓存。

声明在关联另一侧的counter_cache => true选项

class ticket 
    belongs_to :user, :counter_cache => true 
end 

你还需要在你被点名tickets_count用户表中的列。 每当您向用户添加新门票时,rails都会更新此列,因此,当您创建用户记录时,您可以简单地根据此列获取门票数量而无需其他查询。

+0

更新了我的问题,无法更改表格结构 – Fivell 2012-02-09 11:09:19

+0

如果您不能更改表格结构,那么您只需添加一个虚拟方法,该方法返回用户模型中的计数:def tickets_count; @tickets_count || = tickets.count;结束“,然后你可以把它称为一个普通的属性'@ user.tickets_count' – edgarjs 2012-02-21 10:18:47

6

不漂亮,但它的工作原理:

users = User.joins("LEFT JOIN tickets ON users.id = tickets.user_id").select("users.*, count(tickets.id) as ticket_count").group("users.id") 
users.first.ticket_count 
+0

坦克的响应......但它不工作......如果用户没有票据?以及如何按用户分组票数?你试过了吗?此外,我想使用包括 – Fivell 2012-02-17 11:03:37

+0

是的,我试过了,它对我来说工作正常。你为什么要使用包括? – Thilo 2012-02-18 10:23:58

+0

1)连接使用内连接,需要左连接 2)在我们的例子中,user.id语句中的group是什么?(需要统计) – Fivell 2012-02-18 10:39:40

0

怎么样在用户模式,不查询添加一个方法?

你不会修改表结构,或者你不能修改它?

+1

我如何用“includes”动态调用此方法? – Fivell 2012-02-19 22:53:12