0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】投稿一覧に並び替え機能を実装する(新しい順・名前順・ランダム順+昇降順トグル)

Posted at

1. 概要

Rails の投稿一覧ページに「並び替え」機能を追加します。

  • プルダウンで 新しい順 / 名前順 / ランダム順 を選択
  • ボタンで 昇順⇄降順を切り替え
  • 将来、いいね数順やコメント数順などのカスタムソートも簡単に追加可能

2. コントローラを編集

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    # ======== ここから ========
    @sort = params[:sort].presence_in(%w[new name random]) || "new"
    @dir  = params[:dir].presence_in(%w[asc desc]) || "desc"

    base = Post.all

    @posts =
      case @sort
      # 新しい順 / 古い順
      when "new"
        base.order(created_at: @dir)
      # タイトルの昇順 / 降順
      when "name"
        base.order(title: @dir, created_at: :desc)
      # ランダム(DBごとに関数が異なる)
      when "random"
        adapter = ActiveRecord::Base.connection.adapter_name
        func = adapter =~ /mysql/i ? "RAND()" : "RANDOM()"
        base.order(Arel.sql(func))
      else
        base.order(created_at: :desc)
      end
  end
  # ======== ここまで ========
end

コードの解説

1. 並び替え方法を決める

@sort = params[:sort].presence_in(%w[new name random]) || "new"`
  • params[:sort] → URL から「どんな並び順にしたいか」の情報を受け取る
    • 例: /posts?sort=name とアクセスされたら "name" が入る
  • .presence_in(%w[new name random])
    • 「new」「name」「random」の中に含まれているかチェック
    • それ以外の変な値なら nil を返す
  • || "new"
    • nil だったときの保険で "new"(新しい順)をデフォルトにする

2. 並び替えを実行する

@posts =
  case @sort
  when "new"
    base.order(created_at: @dir)
  • case @sort
  • 決めた並び替えの種類に応じて処理を分ける
  • when "new"
    • 並び替え方法が "new"(新しい順)の場合
  • base.order(created_at: @dir)
    • 投稿を作成日時(created_at)で並べ替える
    • @dir"desc" → 新しい順
    • @dir"asc" → 古い順

3. ビューを編集

app/views/posts/index.html.erb
<div class="sort-toolbar">
  <%= form_with url: posts_path, method: :get, local: true do %>
    <label>並び替え:</label>
    <%= select_tag :sort,
          options_for_select([["新しい順","new"],
                              ["名前順","name"],
                              ["ランダム","random"]], @sort),
          onchange: "this.form.submit()" %>

    <%= hidden_field_tag :dir, @dir %>
    <noscript><%= submit_tag "適用" %></noscript>
  <% end %>

  <% next_dir = (@dir == "asc" ? "desc" : "asc") %>
  <%= link_to (@dir == "asc" ? "昇順 → 降順" : "降順 → 昇順"),
              url_for(params.permit(:sort, :page).merge(dir: next_dir)),
              class: "btn-toggle" %>
</div>

1. 全体の役割

この <div class="sort-toolbar"> は、

  • プルダウン(select)で どの種類で並べ替えるか を選ぶ
  • ボタン(link_to)で 昇順⇄降順を切り替える

2. プルダウン部分

<%= form_with url: posts_path, method: :get, local: true do %>
  <label>並び替え:</label>
  <%= select_tag :sort,
        options_for_select([["新しい順","new"],
                            ["名前順","name"],
                            ["ランダム","random"]], @sort),
        onchange: "this.form.submit()" %>

  <%= hidden_field_tag :dir, @dir %>
  <noscript><%= submit_tag "適用" %></noscript>
<% end %>
  • form_with url: posts_path, method: :get
    → 投稿一覧ページに GETリクエスト を送るフォーム
  • select_tag :sort, options_for_select(...)
    → プルダウンを作成
    • ["新しい順","new"] → 表示は「新しい順」、送信される値は "new"
    • @sort が現在選ばれている値
  • onchange: "this.form.submit()"
    → プルダウンを変更した瞬間にフォームを送信(自動でリロード)
  • hidden_field_tag :dir, @dir
    → いまの「昇順/降順」も一緒に送信して保持するための隠しフィールド
  • <noscript>
    → JavaScript が無効なとき用に「適用ボタン」を表示

3. 昇順⇄降順の切替ボタン

<% next_dir = (@dir == "asc" ? "desc" : "asc") %>
<%= link_to (@dir == "asc" ? "昇順 → 降順" : "降順 → 昇順"),
            url_for(params.permit(:sort, :page).merge(dir: next_dir)),
            class: "btn-toggle" %>
  • next_dir = (@dir == "asc" ? "desc" : "asc")
    → 今が昇順なら「次は降順」、今が降順なら「次は昇順」をセット
  • link_to
    → 表示ラベルは「昇順 → 降順」または「降順 → 昇順」
    → クリックすると URL に ?dir=asc または ?dir=desc を付けてアクセス
  • url_for(params.permit(:sort, :page).merge(dir: next_dir))
    → いまの sortpage を引き継ぎつつ、dir だけ切り替える

4. 並び替えを追加する方法

1. コントローラ側にロジックを追加

app/controllers/posts_controller.rb
    when "name"
      base.order(title: @dir, created_at: :desc)

    # ======== ここに追加! =========

    when "random"
      adapter = ActiveRecord::Base.connection.adapter_name

例: いいね数順

app/controllers/posts_controller.rb
when "likes"
  base.order(likes_count: @dir)

例: コメント数順

app/controllers/posts_controller.rb
when "comments"
  base.left_joins(:comments).group(:id).order("COUNT(comments.id) #{@dir.upcase}")

例: ユーザー名順(ログインなしでもOK)

app/controllers/posts_controller.rb
when "user_name"
  base.joins(:user).order("users.name #{@dir.upcase}")

2. ビュー(プルダウンの項目に追加)

app/views/posts/index.html.erb
  <%= select_tag :sort,
        options_for_select([
          ["新しい順","new"],
          ["名前順","name"],

          # ======== ここに追加! ========
          
          ["ランダム","random"]
        ], @sort),
        onchange: "this.form.submit()" %>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?