カウント

こんなコードを書いた

before24h = (Time.now - (60 * 60 * 24)).strftime("%Y-%m-%d %H:%M:%S")

# [[2, 4], [nil, 18], [1, 34]] といった [user_id, count] の配列が返る
counts = Item.count(
  :group => :user_id,
  :conditions => "updated_on > '#{before24h}'"
)

# 登録数の多い順にソートし、
# user_id が nil (anonymous ユーザー) のを除き、
# 20件だけとり、
# ユーザーを引っ張ってくる。
@active_users = counts.sort{|a,b| b[1] <=> a[1] }.select{|e| e[0]}[0..20].map{|e| [User.find(e[0]), e[1]] }

ぜってー inject が使えるって直感でわかるのだが「考えるのをやめた」。挑戦を待つ!(コード読めなくなるから採用しないけど)


追記:

counts = Item.count(:group => :user_id, :conditions => ["updated_on > ?", (Time.now - (60 * 60 * 24))])
@active_users_counts = counts.select{|e| e[0]}.sort_by{|e| -e[1]}[0..20].map{|e| [User.find(e[0]), e[1]] }

conditions に Time オブジェクト突っ込むのと sort_by 使ってみた。user とカウントの組が欲しいんだけど、ActiveRecord#count で工夫すれば一発でとれるのかしら?
:group と :conditions と :include と :order と :limit と掛け合わせると全体のカウントしかとれなかったんだけどなぁ。:in で突っ込むのはー、んーと、zip の逆ってどうやるんだっけ?


追記:

@active_users_counts = Item.count(
  :group => :user_id,
  :order => "count(*) desc",
  :limit => 20,
  :conditions => [
    "(updated_on > ?) AND (user_id is not NULL)", 
    (Time.now - (60 * 60 * 24))
  ]
).map{|e| [User.find(e[0]), e[1]] }

user_id とカウントの組まで取れた。あと user が取れればいいんだけど。