各ユーザーがログイン、質問投稿、投稿に対する回答ができるアプリがある。
質問一覧画面の表示を回答数順に並び替えさせる。
※本筋とは関係ありませんがページネーション機能として
gemfile にkaminari を導入しております
1.モデル
ユーザーを表すmemberモデル、投稿した質問に関するpostモデル、
質問に対する回答を表すanswerモデルがそれぞれある。
各モデルの関係は以下
class Answer < ApplicationRecord
belongs_to :member
belongs_to :post
end
class Post < ApplicationRecord
has_many :answers, dependent: :destroy
belongs_to :member
end
class Member < ApplicationRecord
has_many :answers, dependent: :destroy
has_many :posts, dependent: :destroy
end
2. コントローラーファイル
postコントローラーについては以下
質問一覧を見れるpost.index画面では更新日時順やid順等、
色んな並べ替えのパターンを用意。ここに回答数順も表示させたい。
class PostsController < ApplicationController
def index # 質問一覧を表示する画面
@posts = Post.all
@range = params[:range] # 並べ替え選択時のページネーションを場合分け
case @range
when "投稿Noが新しい順に"
@posts = Post.all.order(id: 'DESC').page(params[:page]).per(10)
when "投稿Noが古い順に"
@posts = Post.all.order(id: 'ASC').page(params[:page]).per(10)
when "更新日時が新しい順に"
@posts = Post.all.order(updated_at: 'DESC').page(params[:page]).per(10)
when "更新日時が古い順に"
@posts = Post.all.order(updated_at: 'ASC').page(params[:page]).per(10)
when "回答数の多い順に"
@posts = Post.joins(:answers).order('count(member_id) desc').group(:post_id).page(params[:page]).per(10)
when "回答数の少ない順に"
@posts = Post.joins(:answers).order('count(member_id) asc').group(:post_id).page(params[:page]).per(10)
...
end
end
def show # 投稿内容を見れる画面
@post = Post.find(params[:id])
end
.....
更新日時順等はpostモデルのカラムをorderで並び替えるだけなので楽。
回答数順の並べ変えは表示方法として
中間テーブル(answer)をjoinさせる、post_idでグルーピング、member_idの数で並び替える
方法を使用する。以下記事を参考とさせていただきました。
3.viewファイル
以下については割愛
・posts/show.html.erb(質問投稿詳細画面)
postのindex画面を記載する
# 並べ替え方法をプルダウンで選択
<%= form_with url: posts_path, local: true, method: :get do |f| %>
<%= f.select :range, options_for_select([['投稿Noが新しい順に'],['投稿Noが古い順に'],['更新日時が新しい順に'],['更新日時が古い順に'],["回答数の多い順に"],["回答数の少ない順に"]]) %>
<%= f.submit "回答並べ替え", data: {"turbolinks"=>false} %>
<% end %>
<%= paginate @posts %>
# 質問一覧を表示させる
(~省略~)
<% @posts.each do |post| %>
<%= post.updated_at.to_s(:datetime_jp) %>
<%= post.answers.count %>
(~省略~)
<% end %>
4.エラー発生
この時点で開発環境では回答数順に並べ替えさせて表示させることには成功した。
しかし、本番環境(インフラはAws/DBはmysqlを使用)
では上手く行かず以下エラーが発生してしまった。
ActionView::Template::Error (Mysql2::Error: Column 'member_id' in order clause is ambiguous: SELECT `posts`.* FROM `posts` INNER JOIN `answers` ON `answers`.`post_id` = `posts`.`id` GROUP BY `post_id` ORDER BY count(member_id) desc LIMIT 10 OFFSET 0):
member_idがどのテーブルのものか不明瞭であることが原因と思われる
ゆえにコントローラーファイルの記述を
「count(member_id)」→「count(answers.member_id)」
に変更する
するとエラーが発生せず回答数順に表示させることができた。
5. 余談
・参考記事そのままで成功しなかったのは、当方ではmemberモデルとpostモデルでも
1対多の関係があったためと考えます。
・この並べ替え方法では回答数0のものを表示させることができません。
→回答数0ものはpostモデルとmemberモデルがanswerモデルに紐づいていないため
回答数0の一覧を表示させるには以下記事を参考