[rails 初心者]同率順位を踏まえたランキング機能（修正版）

<h2>初めに

前回作成したランキング機能にて、**１点だけ**動作不備が見つかりました。
今回はそのバグを解消する記事になります。
(因みに前回の記事をまだ読んでいないという方は、前提条件のところにリンクがあるので
よかったら読んでみて下さい！！)


<h2>前提条件</h2>

`前回までの記事`が一通り終了していること(因みに次の３つです)
①**レビューの基本**　＝　評価関係の処理についてまとめた記事です
②**レビュー機能＋＠（応用）** ＝　「評価点の`平均値化`」と「その平均値順に`並び替え`」を行いました
③**ランキング機能の追加**　＝　`同率順位を考慮したランキング機能`を実装しました。

<details>
<summary>リンクはこちら</summary>

[[rails初心者]複数権限でのログインを使ったレビューサイトの作成（基本）](https://qiita.com/about10/items/0e376c84022f2ac238d0)
[[rails初心者]複数権限でのログインを使ったレビューサイトの作成（応用）](https://qiita.com/about10/items/24e7ed9f1ae16ea0f548)
[[rails 初心者]同率順位を踏まえたランキング機能](https://qiita.com/about10/items/06960f50f22c05683212)

</details>
<h2>バグについて</h2>

・`まだ一度も評価されたことのない`業者がランキングに反映されていませんでした。

<h2>主なやること</h2>

・コントローラの編集（配列に配列を追加）

<h2>開発環境</h2>
・rails 6.1.7<br>
・ruby 3.1.2 <br>
・raty 3.1.1<br>
・jquery 3.6.1<br>
・bootstrap 4.5

<h2>コントローラの記述</h2>
<h4>配列に配列を追加</h4>

早速ですが、修正版を載せたいと思います。
```:app/controllers/平均値を表示したいファイルに関係するコントローラ
  def アクション名
    same_rate = 0
    rank = 1
    #最低一回は評価されたことのあるtraderのデータを取得
    reviews = Review.group(:trader_id).order('avg(star) desc').pluck(:trader_id)
    traders = Trader.find(reviews)
    #一度も評価されたことがないtraderのデータを取得
    not_traders = Trader.where.not(id: Review.group(:trader_id).order('avg(star) desc').pluck(:trader_id))
    not_traders.each {|trader|  traders.push(trader)}

    traders = traders.map.with_index(1) do |trader, i|
      if i == 1 #ランキング処理の一番最初だけ以下の処理
        same_rate = trader.review_average #一番最初だけ「same_rate」に値が入っていないので、先に値を入れる
      end
      if trader.review_average != same_rate #同率順位がない場合以下の処理
        rank = i #同率が無いので、順位を更新
        same_rate = trader.review_average #「same_rate」に現在の値を代入 → 次の値と比べる用として運用するイメージ
        {trader: trader, index: rank } #[trader = trader]という配列と[index = rank]という配列それぞれをセットにしている
      else #同率順位がある場合以下の処理
        same_rate = trader.review_average
        {trader: trader, index: rank }
      end
    end

  @traders = Kaminari.paginate_array(traders).page(params[:page]).per(5)
  #Kaminari.paginate_array → pageメソッドを配列（Rubyの型）に対して用いる場合に必要な記述
```

こんな感じのプログラムに書き換えると、無事不具合を解消することができました！！

これだけだと何がどうのように変わったのか分かり辛いので、
まずは前回から変わった点について解説したいと思います。

<h4>修正点１</h4>

変数の`traders`の文章が長かったので３分割にしました。
※今回の不具合解消には関係ない部分ですが、変更したので一応　(´ﾟдﾟ｀)ｶﾝｹｲﾅｲﾝｶｲ

具体的には次の箇所です（さっきのコントローラの記述から持ってきています）

```:変更箇所
    reviews = Review.group(:trader_id).order('avg(star) desc').pluck(:trader_id)
        #評価点の平均値算出と並び替えを行う

    traders = Trader.find(reviews)
        #さっき定義したreviewsをtraderに紐づけする

    traders = traders.map.with_index(1) do |trader, i|
        #さっきの配列（traders）とランキング化するにあたって使う配列（with_index）を一つにまとめる
```

これについては前回の記事で解説しているので、詳しい説明は割愛させていただきます。

:::note info
ポイント：前回の書き方だと長い文章になってしまったので、３分割にした
:::

<h4>修正点２</h4>

二つ目の修正点はズバリ・・・「取得されていない`trader`の情報を取得する」ことです
先程のプログラミングで言うと、次の部分です
```:変更箇所
    #一度も評価されたことがないtraderのデータを取得
    not_traders = Trader.where.not(id: Review.group(:trader_id).order('avg(star) desc').pluck(:trader_id))
```

:::note info
ポイント①`where.not`により取得されていないデータを参照することが可能になる
ポイント②where.not`(id:`と宣言することで、取得されていない`trader.id`を検索ワードとして設定している
ポイント③`Review.group以下略`は、情報が取得済みの`trader側`と同じ働きをする
:::

<h4>修正点３</h4>

続いての修正点は、`配列と配列を合わせる`ことです。
これも先程のプログラミングで使って説明します。

```:変更箇所
    not_traders.each {|trader|  traders.push(trader)}
```
:::note info
ポイント①`push`メソッドを使うことで**配列と配列を合わせる**ことができる
ポイント②`not_traders.each{}`では`not_traders`で取得した配列をもとに`{}`内の処理を一通り実行する
ポイント③`|trader|`は`not_traders`で取得した`trader`情報を一つづつ参照する
ポイント④`traders.push(trader)`は**評価されたことのある方**の業者達(traders)と**評価されたことのない**業者(trader)を`push`する
ポイント⑤`traders.push(trader)`の`（trader）`は、厳密に言えば`|trader|`で参照された業者情報が入る
:::

これだけだと「(。´・ω・)ん?」※これ自分ですｗ
となるので、分かりやすく図解したいと思います。

まず今回の不具合の内容は「まだ**一度も評価されたことのない業者**がランキング表示されていない」ことでした
つまり`「評価されたことのある業者達（配列１）」＋「一度も評価されていない業者達（配列２）」`を処理してしまえばいいことになります。

ではこれを踏まえたうえで、実際に行った処理についてです。
簡単にまとめると
次の画像の赤枠部分を`配列１（traders）`、`配列２（trader）`としました。

![qiita用2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822721/9a313ed0-37f5-53ce-7729-ff17867baad2.png)


つまり、`traders.push(trader)`について、こんな感じにイメージできればOKです。

:::note info
`traders`部分＝**レビューされたことがある業者**の変数（厳密には業者情報とランキングの情報の二つ）
`trader`部分＝**レビューされたことがない業者**の変数（こちらは業者情報のみ）
:::

<h2>完成イメージ</h2>

以上で、平均点0.0の業者がランキングに反映されるようになりました
![qiita用3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822721/31df0ae4-fecb-8f0e-30b7-4d457a57ee85.png)


<h2>さいごに</h2>

　今回の作業は、どちらかというと応用になるランキング機能の修正でした。量は少ないですが、難しく感じた部分がたくさんありました。

　例えばオブジェクト指向を考える時、どの情報が足りないのかを真っ先に把握すればいいところ、先に`push`について探してしまったり。。。ランキングの配列について考えた際には、結果的には前の順位（評価されたことのある業者の順位）を継承するため`not_traders`では作成しませんでしたが、作業の序盤ではランキング用の配列を`not_traders`にも作ろうとしました。その結果頭が混乱する状況に陥ってしまったことも(-_-;)

　このように順番がバラバラによって２度手間３度手間に合った場面がありました。エラーや不具合を修正する際は、一つ一つの問題を根気強く紐解いていく忍耐力も必要だということでしょう（多分）

　自走力をつけるためにもこう言った目に見えないスキル？をレベルアップしていきたいと思います(^^ゞ

今回も最後まで読んでいただきありがとうございました。！！
※まだ学習中の身なので理解不足・誤りがあったらコメント頂けますと幸いです。m(__)m<ﾖﾛｼｸｵﾈｶﾞｲｼﾏｽ