前説
何事も省力化できる人間が強い。
軽く、本日の成果発表!!!と個人の備忘録みたいになってきました。あの、特に進捗ないです。
その中から生まれた貴重な進捗。
この回の続きですね。
できた!と思ったら次々出てきた問題点。とても勉強になる鉞でした。
時間に終われ、本日も0時ギリギリに記事を書き上げます。
そのため、コードは少しダサいです。
前提
Rails 4.2
実装
- いいね!ランキング機能の改良(N+1を一部解決)
- 投稿数ランキング、フォロワーランキングの実装
コード
products_controller.rb
def ranking
#いいね機能
@like = Like.find_by(user_id: current_user.id)
@likes = Like.new(user_id: current_user.id, product_id: params[:product_id])
#ランキング機能
#
# この辺同じようなコードを書いているので共通項見つけて統一させてと思ったが時間の問題でできなかった
#
# group(レコード配列)->order(レコード配列)->limit(レコード配列)->count(ハッシュ)
# いいね数ランキング
@like_count_id_hash = Like.group(:product_id).order('count_product_id DESC').limit(10).count(:product_id)
@like_count_id = @like_count_id_hash.keys
#いいね順にツイートを取得する
@like_count_product = Product.includes(:user,:likes,:taggings,:like_users).where(id: @like_count_id).index_by(&:id)
#投稿数ランキング
@product_count_id_hash = Product.group(:user_id).order('count_user_id DESC').limit(5).count(:user_id)
@product_count_id = @product_count_id_hash.keys
#投稿数順にユーザーを取得する
@product_count_user = User.where(id: @product_count_id).index_by(&:id)
#フォロワーランキング
@follow_count_id_hash = Follow.group(:followable_id).order('count_followable_id DESC').limit(5).count(:followable_id)
@follow_count_id = @follow_count_id_hash.keys
#フォロワー順にユーザーを取得する
@follow_count_user = User.where(id: @follow_count_id).index_by(&:id)
end
上のコードは同じような記述を三度行なっている。本来であれば、もっとシンプルになるはず。
コードとしては個人的に全く満足していない。冗長。
view/products/ranking_html.erb
<div class="container">
<div class="row">
<div class="col s12">
#タブの切り替え
<ul class="tabs">
<li class="tab col s4"><a href="#test1" class="active">いいね数</a></li>
<li class="tab col s4"><a href="#test2">投稿ユーザー</a></li>
<li class="tab col s4"><a href="#test3">フォロワーユーザー</a></li>
</ul>
#いいねランキング
<div id="test1">
<div class="col s6">
<% @like_count_id.each do |a_product| %>
<h4><%= @like_count_id.index(a_product)+1 %>位<br></h4>
<h5><%= @like_count_id_hash[a_product] %>いいね!</h5>
<ul class="card">
#ツイート情報の部分テンプレート
<%= render 'products/product' , a_product: @like_count_product[a_product] %>
</ul>
<% end %>
</div>
</div>
#投稿数ランキング
<div id="test2">
<% @product_count_id.each do |a_user| %>
<h4><%= @product_count_id.index(a_user)+1 %>位</h4>
<h5><%= @product_count_id_hash[a_user] %>ツイート</h5>
<ul class="user-index">
#ユーザー情報の部分テンプレート
<%= render 'products/user', user: @product_count_user[a_user] %>
</ul>
<% end %>
</div>
#フォロワーランキング
<div id="test3">
<% @follow_count_id.each do |a_user| %>
<h4><%= @follow_count_id.index(a_user)+1 %>位</h4>
<h5><%= @follow_count_user[a_user].followers_count %>人</h5>
<ul class="user-index">
#ユーザー情報の部分テンプレート
<%= render 'products/user', user: @follow_count_user[a_user] %>
</ul>
<% end %>
</div>
</div>
</div>
</div>
どんな感じか
フォロワーランキング
投稿数ランキング
実装はできてる。最低限のことはできてるぞおおお!!!
クエリは一体どうなってる?
元々、ユーザーを毎度呼び出していた。
他にも様々なN+1が発生していて荒れていた。
大抵のN+1はincludesメソッドのおかげで直りました!
現在は・・・
フォロワー関連とタグ関連で毎度クエリを発行していた。
うーーん・・・この・・・感。
最後に
次にやることは・・・
- N+1問題を完全に駆逐したい
- コードの省力化、効率化
- デザインをつける
初心者ですので鉞やアドバイスがあればよろしくお願いします。
全身全霊で対処させていただきます。