【Rails+Redis+Docker】RailsアプリにRedis導入&ランキングの実装


Redisの導入

今回使うRedisはブログサイトでよくあるランキングを表示するために使います。

まずRailsとRedisの接続からしないといけないのですが、ここで2日くらい躓きました。色んなサイトを見まくって試したけど全然繋がらない状態が続き地獄でした。

解決方法

基本的にredisはlocalhost:6379に繋ぐのが普通なのですが、開発段階だとRails自体をlocalhostに繋いでるので混同しちゃって上手く繋がらなくなってしまっていたということでした。

なのでredisの設定をlocalhost→redisといった感じに名前を変更して行えばすんなり上手くいった感じです。

出来てしまえば簡単なことだったと思うのですが、やはり初心者には結構辛いところでした。コード打っててエラーならまだしも繋がらなくてエラーは精神的にかなりきます。

以下は変更点と参考サイトです。

https://stackoverflow.com/questions/34729752/sidekiq-error-connecting-to-redis-on-127-0-0-16379-errnoeconnrefused-on-doc】

ちなみにdocker-compose.ymlはこんな感じです。

docker-compose.yml
version: '3'

 services:
   db:
     image: mysql:8.0.17
     command: mysqld --default-authentication-plugin=mysql_native_password
     volumes:
       - ./db/mysql_data:/var/lib/mysql 
     environment:
       MYSQL_ROOT_PASSWORD: root
       MYSQL_DATABASE: root
     ports:
       - "4306:3306"

   web:
     build: .
     command: bundle exec rails s -p 3000 -b '0.0.0.0'
     volumes:
       - .:/app_name
     ports:
       - "3000:3000"
     depends_on:
       - db
       - redis
     tty: true
     stdin_open: true
     links:
       - db
     environment:
       REDIS_HOST: redis
       REDIS_PORT: 6379

   redis:
     image: redis:5.0.5
     ports:
       - 6379:6379
     volumes:
       - ./redis:/data
     command: redis-server --appendonly yes

Redisでランキング機能の実装

無事redisは導入出来ましたが、「導入出来てしまえばこっちのもん!」というわけではありません。

ランキングを表示しないといけないのでこれまたredisの基礎とcontroller、viewを見直さないといけません。

これも「Rails redis ランキング」と調べたら結構参考サイトは出てくるのですが、仕組みの理解が乏しいので基礎の見直しが必要でした。

redisの特徴としては以下のような感じです。

  • インメモリアルデータベース(すごく早い!)…ランキングなどに向いてる
  • 永続化(定期的にディスクに書き出す)
  • データ構造サーバー

そんなredisをRailsで使うには、gemでredisを導入してREDISメソッドを利用する必要があります。

gemの導入が完了したらconfig/initialize以下にredis.rbを作成して以下を記入。

config/initialize/redis.rb
require 'redis'

uri = URI.parse(ENV["REDIS"])
REDIS = Redis.new(host: uri.host, port: uri.port)
post_controller.rb
  def index
     @posts = Post.all
     ids = REDIS.zrevrangebyscore "posts/daily/#{Date.today.to_s}", "+inf", 0,limit:[0,3]
     @ranking_posts = ids.map{ |id| Post.find(id) }
   end

   # GET /posts/1
   # GET /posts/1.json
   def show
     REDIS.zincrby "posts/daily/#{Date.today.to_s}", 1, @post.id
   end 

今回はredisのソート済みセットを使ってpv数ランキングを実装していきました。
pv数の表示はviewに直接以下のように書けば表示されます。

index.rb
<ul>
   <% @ranking_posts.each do |ranking_post| %>
       <li>
         <%= link_to(ranking_post.title,"/posts/#{ranking_post.id}") %>
         (<%= REDIS.zscore("posts/daily/#{Date.today.to_s}", ranking_post.id).to_i %>PV)
       </li>
   <% end %>
</ul>

アクションに設置する方法がないか考えたのですが、これしか方法がわからなかったです。ちょっと見苦しいですがとりあえずこれでPV数が表示されます。

まとめ

Redisの理解はまだまだ乏しいのですが、触ってると結構楽しかったのでまた利用してみたいと思います。