はじめに
50音順でカテゴリを並べてページネーションを行う場合は、sort_by
メソッドを使って配列に変換した後、Kaminari.paginate_array
メソッドを使ってページネーションを行う。
最終的な解決策
sort_order = params[:sort] == 'desc' ? :desc : :asc
@categories = current_company.categories.order(name: sort_order).page(params[:page]).per(10)
試行錯誤の過程
1. データベースレベルでの50音順並べ替えの試み
最初に試したのは、PostgreSQLの機能を利用して50音順に並び替えを試みる方法。
# コントローラー
@categories = current_company.categories.order('name COLLATE "ja_JP.utf8"').page(params[:page]).per(10)
または
@categories = current_company.order(Arel.sql('name COLLATE "ja_JP.utf8"')).page(params[:page]).per(10)
これによるエラーメッセージ:
ActiveRecord::StatementInvalid: PG::UndefinedObject: ERROR: collation "ja_JP.utf8" for encoding "UTF8" does not exist
このエラーから、PostgreSQLのロケール設定に問題があることが分かる。
2. Rubyの配列操作を用いた50音順並び替え
次にRubyの配列操作で並び替えを試みた。これはメモリ上での操作になるので、全てのレコードをメモリにロードしてから並び替える。
# コントローラー
@pre_categories = current_company.categories.to_a.sort_by { |category| category.name }
@categories = Kaminari.paginate_array(@pre_categories).page(params[:page]).per(10)
この場合は以下のエラーが出た。
NoMethodError at /categories/6 undefined method `page'
上記は、KaminariのpageメソッドがActiveRecordのリレーションオブジェクトに適用されることを期待しているにもかかわらず、to_aで配列に変換すると、その配列はpageメソッドを使用できないために生じるエラーである。
配列にページネーションを適用したい場合、KaminariのKaminari.paginate_arrayメソッドを使用することで解決できる。以下のようにコントローラのコードを修正する。
pre_categories = current_company.categories.sort_by { |category| category.name }
@categories = Kaminari.paginate_array(pre_categories).page(params[:page]).per(10)
この方法はうまくいき、50音順に並び替えた配列に対してページネーションを適用することができた。ただし、アプリケーションレベルでの並べ替えとなる。
試行錯誤した理由と結果の記録
データベースレベルでの並び替えを最初に試みたのは、大量のデータがある場合にサーバーのメモリリソースを消費しないようにするためだった。しかし、データベースのロケール設定に問題があったため、この方法は採用できなかった。
次に、Rubyの配列操作を用いた方法を試したが、これはサーバーのメモリに全カテゴリをロードする必要があり、データセットが大きくなると問題が生じる可能性があった。ただし、現在のアプリケーションではカテゴリの数が多くないため、この方法で十分だった。