初めに
前回作成したランキング機能にて、1点だけ動作不備が見つかりました。
今回はそのバグを解消する記事になります。
(因みに前回の記事をまだ読んでいないという方は、前提条件のところにリンクがあるので
よかったら読んでみて下さい!!)
前提条件
前回までの記事
が一通り終了していること(因みに次の3つです)
①レビューの基本 = 評価関係の処理についてまとめた記事です
②レビュー機能+@(応用) = 「評価点の平均値化
」と「その平均値順に並び替え
」を行いました
③ランキング機能の追加 = 同率順位を考慮したランキング機能
を実装しました。
リンクはこちら
[rails初心者]複数権限でのログインを使ったレビューサイトの作成(基本)
[rails初心者]複数権限でのログインを使ったレビューサイトの作成(応用)
[rails 初心者]同率順位を踏まえたランキング機能
バグについて
・まだ一度も評価されたことのない
業者がランキングに反映されていませんでした。
主なやること
・コントローラの編集(配列に配列を追加)
開発環境
・rails 6.1.7・ruby 3.1.2
・raty 3.1.1
・jquery 3.6.1
・bootstrap 4.5
コントローラの記述
配列に配列を追加
早速ですが、修正版を載せたいと思います。
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の型)に対して用いる場合に必要な記述
こんな感じのプログラムに書き換えると、無事不具合を解消することができました!!
これだけだと何がどうのように変わったのか分かり辛いので、
まずは前回から変わった点について解説したいと思います。
修正点1
変数のtraders
の文章が長かったので3分割にしました。
※今回の不具合解消には関係ない部分ですが、変更したので一応 (´゚д゚`)カンケイナインカイ
具体的には次の箇所です(さっきのコントローラの記述から持ってきています)
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)を一つにまとめる
これについては前回の記事で解説しているので、詳しい説明は割愛させていただきます。
ポイント:前回の書き方だと長い文章になってしまったので、3分割にした
修正点2
二つ目の修正点はズバリ・・・「取得されていないtrader
の情報を取得する」ことです
先程のプログラミングで言うと、次の部分です
#一度も評価されたことがないtraderのデータを取得
not_traders = Trader.where.not(id: Review.group(:trader_id).order('avg(star) desc').pluck(:trader_id))
ポイント①where.not
により取得されていないデータを参照することが可能になる
ポイント②where.not(id:
と宣言することで、取得されていないtrader.id
を検索ワードとして設定している
ポイント③Review.group以下略
は、情報が取得済みのtrader側
と同じ働きをする
修正点3
続いての修正点は、配列と配列を合わせる
ことです。
これも先程のプログラミングで使って説明します。
not_traders.each {|trader| traders.push(trader)}
ポイント①push
メソッドを使うことで配列と配列を合わせることができる
ポイント②not_traders.each{}
ではnot_traders
で取得した配列をもとに{}
内の処理を一通り実行する
ポイント③|trader|
はnot_traders
で取得したtrader
情報を一つづつ参照する
ポイント④traders.push(trader)
は評価されたことのある方の業者達(traders)と評価されたことのない業者(trader)をpush
する
ポイント⑤traders.push(trader)
の(trader)
は、厳密に言えば|trader|
で参照された業者情報が入る
これだけだと「(。´・ω・)ん?」※これ自分ですw
となるので、分かりやすく図解したいと思います。
まず今回の不具合の内容は「まだ一度も評価されたことのない業者がランキング表示されていない」ことでした
つまり「評価されたことのある業者達(配列1)」+「一度も評価されていない業者達(配列2)」
を処理してしまえばいいことになります。
ではこれを踏まえたうえで、実際に行った処理についてです。
簡単にまとめると
次の画像の赤枠部分を配列1(traders)
、配列2(trader)
としました。
つまり、traders.push(trader)
について、こんな感じにイメージできればOKです。
traders
部分=レビューされたことがある業者の変数(厳密には業者情報とランキングの情報の二つ)
trader
部分=レビューされたことがない業者の変数(こちらは業者情報のみ)
完成イメージ
以上で、平均点0.0の業者がランキングに反映されるようになりました
さいごに
今回の作業は、どちらかというと応用になるランキング機能の修正でした。量は少ないですが、難しく感じた部分がたくさんありました。
例えばオブジェクト指向を考える時、どの情報が足りないのかを真っ先に把握すればいいところ、先にpush
について探してしまったり。。。ランキングの配列について考えた際には、結果的には前の順位(評価されたことのある業者の順位)を継承するためnot_traders
では作成しませんでしたが、作業の序盤ではランキング用の配列をnot_traders
にも作ろうとしました。その結果頭が混乱する状況に陥ってしまったことも(-_-;)
このように順番がバラバラによって2度手間3度手間に合った場面がありました。エラーや不具合を修正する際は、一つ一つの問題を根気強く紐解いていく忍耐力も必要だということでしょう(多分)
自走力をつけるためにもこう言った目に見えないスキル?をレベルアップしていきたいと思います(^^ゞ
今回も最後まで読んでいただきありがとうございました。!!
※まだ学習中の身なので理解不足・誤りがあったらコメント頂けますと幸いです。m(__)m<ヨロシクオネガイシマス