[Rails]カテゴリーランキングの作り方[ruby]

プログラミング

はじめに

フリマアプリのクローンサイトを作成しています。必須機能に加えて、オリジナル機能を付けようと思います。

実現したいこと

出品されている商品のカテゴリーが多い順に取得して表示するランキング機能を実装します。

実装

カテゴリーのDB作成

親子関係を持つカテゴリーはanecestryというgemを使うと便利です。導入の仕方は他に記事がたくさんあるので、それを参考にして下さい。参考までにseedsのデータを置いておきます。

ladys = Category.create(name: "レディース")

ladys_tops = ladys.children.create(name: "トップス")
ladys_jacket = ladys.children.create(name: "ジャケット/アウター")
ladys_pants = ladys.children.create(name: "パンツ")

ladys_tops.children.create([{name: "Tシャツ/カットソー(半袖/袖なし)"},
                            {name: "Tシャツ/カットソー(七分/長袖)"},
                            {name: "シャツ/ブラウス(半袖/袖なし)"},
                            {name: "Tシャツ/ブラウス(七分/長袖)"},
                            {name: "ポロシャツ"},
                            {name: "キャミソール"},
                            {name: "タンクトップ"},
                            {name: "ホルターネック"},
                            {name: "ニット/セーター"},
                            {name: "チュニック"},
                            {name: "カーティガン/ボレロ"},
                            {name: "アンサンブル"},
                            {name: "ベスト/ジレ"},
                            {name: "パーカー"}])

レディースの子カテゴリーにトップス、ジャケット/アウターなどがあり、トップスの子カテゴリーにTシャツ/カットソー(半袖/袖なし)などがあります。

ルートの設定

Rails.application.routes.draw do
  devise_for :users
  root to: 'items#index'
  resources :ranks, only: [:index]
end

なんでもいいですが、コントローラの名前は”ranks”にしておきます。また、indexアクションしか使いません。

コントローラの設定

class RanksController < ApplicationController
  def index
    @trend_categories_id = Item.group(:category_id).order('count_all DESC').limit(5).count.to_a
    @trend_categories_name = Item.joins(:category).group("categories.name").order('count_all DESC').limit(5).count.to_a
  end
end

@trend_categories_id
=> [[45, 6], [150, 4], [277, 3], [243, 2], [223, 1]]
@trend_categories_name
=> [["Tシャツ/カットソー(半袖/袖なし)", 6], ["Tシャツ/カットソー(七分/長袖)", 4], ["小説", 3], ["ベビードレス", 2], ["漫画", 2]]

出品アイテムの情報を持っているItemテーブルと、カテゴリーの情報を持っているCategoryテーブルがあります。
@trend_categories_idに出品が多いカテゴリートップ5のカテゴリーのidが入っています。@trend_categories_nameには、出品が多いカテゴリートップ5のカテゴリーの名前が入っています。
@trend_categories_idはリンクを作るために必要なので、取得しています。

.group(:category_id).count
groupメソッドはテーブルの特定のカラムの数に対してカラム数を取得したいときに使います。
この場合、Itemテーブルのcategory_idに探しに行っています。
そして、countメソッドで、category_idごとの数を取得しています。

.order(‘count_all DESC’)
降順に並べます。つまり、category_idの数が高い順に並べます。

.limit(5)
limitメソッドで取得するデータ数を制限します。ここでは、上から5つのデータを取得します。

.to_a
取り出しやすいように配列化します。

.joins(:category)
@trend_categories_idでは、Itemテーブルのcategory_idの値を取得しましたが、category_idからjoinメソッドを使うことで、Categoryテーブルにcategoryの名前を取得しにいきます。

@trend_categories_id
=> [[45, 6], [150, 4], [277, 3], [243, 1], [223, 1]]

[categories_id, データ数]という形になっています。

@trend_categories_name
=> [[“Tシャツ/カットソー(半袖/袖なし)”, 6], [“Tシャツ/カットソー(七分/長袖)”, 4], ・・・]

[name,データ数]という形になっています。

ビューの設定

.rank
  .rank__icon
    = image_tag "/images/rankfirst.png", class: "rank__icon--first"
  .rank__name
    - if @trend_categories_id[0].present?
      = link_to category_path(@trend_categories_id[0][0]), class: "rank__name--first" do
        = @trend_categories_name[0][0]
    - else
      なし
 .rank__icon
    = image_tag "/images/ranksecond.png", class: "rank__icon--second"
  .rank__name
    - if @trend_categories_id[1].present?
      = link_to category_path(@trend_categories_id[1][0]), class: "rank__name--second" do
        = @trend_categories_name[1][0]
    - else
      なし

if @trend_categories_id[1].present?でデータがある時はカテゴリーの名前を表示して、データがない場合は、”なし”と表示します。

@trend_categories_name[0][0]で一位のカテゴリーの名前を表示しています。二重配列になっているので、このように取り出します。
= link_to category_path(@trend_categories_id[0][0])でリンクのパスを指定するために、@trend_categories_idをここで使っています。これで、カテゴリーごとの商品一覧ページに飛ぶようになっています。

タイトルとURLをコピーしました