2 flat logo on transparent 256
2018-03-21

Ruby On RailsでRedisを利用してランキング機能を実装する

Speed2

Webアプリケーションやスマホアプリを作成していると、ランキングを表示したいという事があると思います。 今回はRuby On RailsとRedisを利用してランキング機能を設定する方法を解説します。

○開発環境○

PC:Mac

プログラミング言語:Ruby2系

フレームワーク:Ruby On Rails4系

Redis(レディース)サーバーとは

メモリ上に値に対して一意のキーをセットし、このペアを 保存するデータベースの一種です。 特徴として一般のデータベースより、超高速に値を読み込む事が可能です。 今回はこのRedisを利用して、PVの情報を格納し、ランキング形式で取り出します。

Macへbrewを利用してredisをダウンロードする

$ brew install redis

下記が表示されればインストールされている

$ redis-server -v
Redis server v=3.0.7

redisを起動する

$ redis-server

以降はRedisを起動した状態で対応

※停止する場合はMacの場合controlキー+Cを選択

Gemにredisを追加

下記をgem fileに追記しインストール

gem 'redis'

initializerにredisファイルを生成

config/initializer/redis.rb を追加

require 'redis'
uri = URI.parse('localhost:6379')
REDIS = Redis.new(host: uri.host, port: uri.port)

2行目のlocalhost:6379の記載はできれば、.envファイルへ記載する事をオススメします。

.envファイルの解説はユーザーのフラグ管理に使えるRuby On Railsのenumを紹介ご参照下さい

Controllerへロジックを設定

ArticlesControllerのshowアクションへPVカウントの設定を追加し、set_rankingのアクションでランキングデータを取得する処理を設定します。

全コード

class ArticlesController < ApplicationController
  before_action :set_ranking

  def show
    @article = Article.find(params[:id])
    REDIS.zincrby "articles/daily/#{Date.today.to_s}", 1, "#{@article.id}"
  end

  def set_ranking_data
    #5件のランキングデータを取得
    ids = REDIS.zrevrangebyscore "articles/daily/#{Date.today.to_s}", "+inf", 0, limit: [0, 5]
    @ranking_articles = Article.where(id: ids)

     #5件未満の場合、公開日時順で値を取得
    if @ranking_articles.count < 5
      adding_articles = Article.order(publish_time: :DESC, updated_at: :DESC).where.not(id: ids).limit(5 - @ranking_articles.count)
      @ranking_articles.concat(adding_articles)
    end
  end
end

各コードの解説

PV数を追加する

ShowアクションのzincrbyメソッドはRedisのメソッドになり、指定したキーに対して、指定されたメンバーに指定値を増加される事ができます。

  def show
    @article = Article.find(params[:id])
    REDIS.zincrby "articles/daily/#{Date.today.to_s}", 1, "#{@article.id}"
  end

Redis内の値イメージ

日時 記事ID PV数
2018-3-1 1 4
2018-3-2 12 5

redis内で値が追加されていくイメージはこのサイトが分かりやすかったです。

byebugしてshowアクションで登録される値を確認すると下記の様に、閲覧毎に値が追加されていきます。

(byebug) REDIS.zincrby "articles/daily/#{Date.today.to_s}", 1, "#{@article.id}"
4.0

ランキングデータを抽出する

set_rankingアクションのzrevrangebyscoreは指定したキーのバリューをscore(PV)順に並び替えてmemberをscoreの高い順に返してくれるメソッドです。"+inf"は値の上限はなしを意味します。0は値下限が0であることを指定しています。

  def set_ranking_data
    ids = REDIS.zrevrangebyscore "articles/daily/#{Date.today.to_s}", "+inf", 0, limit: [0, 5]
    @ranking_articles = Article.where(id: ids)

    if @ranking_articles.count < 5
      adding_articles = Article.order(publish_time: :DESC, updated_at: :DESC).where.not(id: ids).limit(5 - @ranking_articles.count)
      @ranking_articles.concat(adding_articles)
    end
  end

Indexページで呼び出す

index.html.slimで@ranking_articlesのインスタンスをループ処理で回して表示します。

  - @ranking_articles.each do |article
     article.title

その他Railsでアプリケーションを作成する際のオススメの記事は下記

Ruby On Railsとtwitterの投稿機能を連携する

前の記事
次の記事