初めに
Redisでランキングを実装してみました。
こちらのサイトを参考にしました。
RailsでRedisを使うメモ ランキングつくったり
http://o.inchiki.jp/obbr/307
設定
デザインはbootstrap
ダミーデータ作成にfakerをつかいました。
あとredisを使うので
gemfileに
gem 'redis'
gem 'bootstrap'
gem 'jquery-rails'
gem 'popper_js'
gem 'tether-rails'
gem 'faker'
こんな感じで書いてbundle installしました。
userモデルを作成しました。
bootstrapの設定fakerでのダミーデータ作成は省略
実装
users_controllerを
class UsersController < ApplicationController
def index
@ranking_users_data = (REDIS.zrevrangebyscore "users", 10, 0, withscores: true)
end
def add_score
user = User.find params[:id]
REDIS.zincrby "users", 1, user.id
end
end
こんな感じにしました。
REDISに関しては
config/initializers以下にredis.rbを作成して中身に
REDIS = Redis.new(host: "localhost", port: 6379)
と書くことで使えます。
REDIS.zincrby "users", 1, user.id
みたいに書いているところでスコアのカウントをしています。
usersがスコアを計算する大きなまとまりの名前でusersでなくても良いのですが今回はusersと名前を付けています。
そのあとの1が追加する数です
user.idごとにスコアがカウントされていきます。
集められたスコアをソートされた状態で出力するには
REDIS.zrevrangebyscore "users", "+inf", 0, withscores: true
このコードです。
スコアが+inf(最大?)から0まで表示することになっています。
例えばスコアが0から10まで表示したい場合は
REDIS.zrevrangebyscore "users", 10, 0, withscores: true
あくまでスコアなので0から10番目を表示というわけではありません。
自分の場合これだけだと登録されたばかりのuserはredisのusersのランキングの中に入らないので
REDIS.zrevrangebyscore "users", 10, 0, withscores: true
これで表示されませんでした。
なのでuserが作成されたときに1スコアをたして表示されるようにしました。
models/user.rb
class User < ApplicationRecord
after_create{ REDIS.zincrby "users", 1, self.id}
end
routesは
Rails.application.routes.draw do
get 'users/index'
post 'users/add_score/:id', to: 'users#add_score'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
このようにして
viewsは
<br>
<br>
<br>
<br>
<br>
<div class="container">
<table class="table table-dark">
<thead>
<tr>
<th scope="col">Ranking</th>
<th scope="col">Name</th>
<th scope="col">Count</th>
<th scope="col">Like Button</th>
</tr>
</thead>
<tbody>
<% @ranking_users_data.each_with_index do |rank_data,index| %>
<tr>
<th scope="row"><%= index + 1 %></th>
<td><%= user_name(rank_data[0]) %></td>
<td class="count"><%= rank_data[1].to_i %></td>
<td>
<%= button_to "/users/add_score/#{rank_data[0]}", class: "like-btn", id: "addBtn", remote: true do %>
<i class="fas fa-heart" style="font-size: 15px;" data-count="<%= index %>"></i>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<script>
var allBtn = document.getElementsByClassName('like-btn')
var allCount = document.getElementsByClassName('count')
var btnLength = allBtn.length
var addLikeCount = function(i) {
allCount[i].innerHTML = parseInt(allCount[i].innerHTML) + 1
}
for(var i = 0; i < btnLength; i++ ) {
allBtn[i].addEventListener('click', function(a) {
let dataCount = this.getElementsByClassName('fas')[0].dataset.count
addLikeCount(dataCount);
});
}
</script>
例のごとく自分はjavascriptをerbの中に書いています。
とりあえず見た目はこんな感じになると思います。
fontawesomeを使っているので
layoutsのheadの中に
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
を書いて
assets/stylesheets/application.scssに
@import '/*';
@import 'bootstrap';
@import 'tether';
body
{
background: #95a5a6;
}
.like-btn
{
transition: all 0.2s;
border: none !important;
}
.like-btn:hover
{
background: rgb(224, 0, 37) !important;
color: white !important;
border: none !important;
}
こんな感じにしてあると見た目は同じになると思います。
これでクリックされるたびにスコアが追加されていきます。
ちなみに
redisに追加されているデータをみたい場合は
rails cで
REDIS.keys
とすれば登録されているkeyが出て
REDIS.zrevrangebyscore "users", "+inf", 0, withscores: true
と入力すればuser.idとスコアが二次配列の形で表示されると思います。
おわり