10198


railsのウェブアプリでデータベースの中に記事レコード(Post)があり「その中で人気がありかつ新しいものが上」という条件のscopeを定義しようと考えています。  
PostはActsAsVotableでLikeボタンを押すことでLike数をvotesで集計できるようになっています。また記事ごとにアクセス数をposts.view_countに保存しています。

今は「Like数 * 10 + 記事のアクセス数の数値が高いものから（記事の作成日が１ヶ月以内）」という条件で並べています。

`scope :featuring, -> { joins(:votes).where('posts.created_at > ?', Time.now -
1.month).group('posts.id').order('(count(votes.id)*10 + posts.view_count)
DESC, posts.id DESC') }`

この方法ですとLike数がゼロの記事はアクセス数があってもscopeに含まれません。かつ本当に入れたい条件とは少し異なっております。  
本当は  
「１週間以内のLike数 * 100 + 1ヶ月以内のLike数 *10 + 記事のアクセス数の数値が高いものから（記事の作成日が２ヶ月以内）」
という条件にしたいです。  
どのようにすればいいのでしょうか？  
できればscopeで記述したいのですが、無理ならクラス・メソッドでもかまわないと考えています。  
方法はありますでしょうか？  
データベースはPostgreSQLです。


CC BY-SA 3.0
2015-05-14T10:51:51.850
10175
2015-05-15T08:04:51.037
9202
question
ruby-on-rails ruby rails-activerecord sql postgresql
scope定義でcreated_atの日時によりレコードのカウント方法を変えて集計する方法は？


> 「１週間以内のLike数 * 100 + 1ヶ月以内のLike数 *10 + 記事のアクセス数の数値が高いものから（記事の作成日が２ヶ月以内）」
> という条件にしたいです。

たぶん、こんな感じかなーと思います。

[code]

    scope :featuring, -> {
      select("posts.*")
      .joins("LEFT OUTER JOIN votes ON votes.post_id = posts.id") # 実際のテーブル構造に合わせて変更してください
      .where('posts.created_at > ?', 2.months.ago)
      .group('posts.id')
      .order(<<-ORDER_SQL)
    ( SUM(
       CASE WHEN votes.created_at > current_timestamp + '-7 days' THEN 100
            WHEN votes.created_at > current_timestamp + '-31days' THEN 10
            ELSE 0 END
      )
      + posts.view_count
    ) DESC, posts.id DESC
      ORDER_SQL
    }
    
[/code]

全く同じ環境で動作確認することはできないので、エラーが出た場合は適宜修正してください。


CC BY-SA 3.0
2015-05-14T23:32:00.670
10198
2015-05-15T08:04:51.037
2015-05-15T08:04:51.037
85
85
10175
answer