Oasistブログ

自然言語、プログラミング、ライフハックを主に特集

Ransackを使わないソート機能実装

f:id:oasist:20200614004721p:plain
Ruby on Rails

目次

1. 環境

2. 要件

  • 学生テーブル students学生コード (student_code)学生名 (name)学年 (grade_id) でソートしたい。
  • 一覧画面に実装するが、検索フォームがあるのでその結果を保持する。
  • 学生テーブル以外にも今後適用するので、共通処理は纏めておく。

3. カスタムヘルパー実装

3-1. StudentHelper

モデル別にカスタムヘルパーをモジュールを切って実装する。

module StudentHelper
  def student_sort_link(column)
    search_params = search_students_params.empty? ? {} : { search_students_form: search_students_params }
    sort_link(Student.human_attribute_name(column), column, search_params)
  end
end
  • カラム名を引数に取る。
  • 検索パラメータが空の場合、空のハッシュを返す。さもなくばキー値のハッシュを返す
  • 共通処理の sort_link に値を渡す
    • 第一引数: ソート用のリンク文字列。辞書ファイルで日本語に翻訳
    • 第二引数: クエリ文字列 column=[column] を生成する
    • 第三引数: 検索パラメーターのキー値のハッシュ

3-2. ApplicationHelper

共通の処理を記述。

module ApplicationHelper
  def sort_link(column_name, column, **additional_params)
    if params[:column] != column.to_s || params[:direction].nil?
      link_to column_name, { column: column, direction: :asc, **additional_params }
    elsif params[:column] == column.to_s && params[:direction] == 'asc'
      link_to "#{column_name}", { column: column, direction: :desc, **additional_params }
    elsif params[:column] == column.to_s && params[:direction] == 'desc'
      link_to "#{column_name}", { column: column, direction: :asc, **additional_params }
    end
  end
end
  • 第三引数の検索結果のパラメーターは可変長で受け取る
  • 条件分岐は以下の3パターン
    • 現在ソートがかかっているカラムと指定されたカラムが一致しない、もしくは現在ソートがされていない
      • => 指定したカラムで昇順でソートする
    • 現在ソートがかかっているカラムとソート対象のカラムが一致し、なおかつ現在昇順でソートされている
      • => 指定したカラムで降順でソートし、 マークを付ける
    • 現在ソートがかかっているカラムとソート対象のカラムが一致し、なおかつ現在降順でソートされている
      • => 指定したカラムで昇順でソートし、 マークを付ける

4. コントローラー実装

受け取ったクエリ文字列に従ってSQLを走らせる。

def index
  @students = Student.search(@search_form).order(sort_column => sort_direction).preload(:grade)
end

.
.
.

private

def sort_column
  params[:column].in?(%w(student_code name grade_id)) ? params[:column] : :id
end

def sort_direction
  params[:direction].in?(%w(asc desc)) ? params[:direction] : :asc
end
  • order は キー => 値 = ソート対象カラム => ソート順 のハッシュを引数にとる
  • sort_column: 指定したカラムがホワイトリストにあればそれを order のキーに指定し、なければ id を指定する。
  • sort_direction: 指定したソート順がホワイトリストにあればそれを order の値に指定し、なければ昇順を指定する。

5. ビュー実装

呼び出し元では以下のように引数にシンボルを指定する。

<th class="col-sm-2"><%= student_sort_link(:user_code) %></th>
<th class="col-sm-3"><%= student_sort_link(:name) %></th>
<th class="col-sm-2"><%= student_sort_link(:grade_id) %></th>

6. 結果(生徒コードでソート)

  • デフォルト: クエリ文字列なし

f:id:oasist:20200614004949p:plain
クエリ文字列なし


  • 昇順: ?column=user_code&direction=asc

f:id:oasist:20200614005018p:plain
?column=user_code&direction=asc`


  • 降順: ?column=user_code&direction=desc

f:id:oasist:20200614005041p:plain
?column=user_code&direction=desc`