検索結果を指定したプロパティで並び変える際に検索条件を引き継いで、ソートする際に少しハマったのでやり方をメモφ(..)
イメージは下記みたいな、検索後のタスクの一覧を期限の降順で並び替えるような機能を想定してます(・∀・)
検索条件を引き継いでソートする方法
そもそもなぜ検索条件を引き継ぐ必要があるか
何も考えずにソート処理を実装すると下記のような形になるんじゃないかなぁと思うんですが、、、
- 画面上のソートボタンを押下した際にgetパラメータとして項目とソート(降順・昇順)を設定
- controllerでパラメーターを取得し、ソート順を設定しタスクの再取得
- 一覧画面を再描画
上記実装では、少し問題があります。それは、入力された検索条件をcontollerに渡せていないので、ソートボタンを押すと検索条件が未設定の状態で検索処理が行われてしまう恐れがあり下記のように使いにくいものとなってしまいます。。。
検索条件を引き継いでソートを変更する
先程でも書きましたが、問題はソートを行う際にcontrollerに対して既存の検索条件を設定出来ていないために問題が発生してしまっているので、ソート時にも検索条件をパラメーターとして送信する対応を行いましたφ(..)
_order_form.html.haml
でソートする際にhidden_tag
を使って検索条件も合わせてgetパラメーターとして送信するようにしています。
index.html.haml
= render partial: 'search_form', locals: { search_attr: @search_attr } %table{ border: 1 } %thead %tr %th= Task.human_attribute_name(:title) %th= Task.human_attribute_name(:status) %th = Task.human_attribute_name(:priority) = render partial: 'order_form', locals: { target: 'priority', search_attr: @search_attr, order: 'asc' } = render partial: 'order_form', locals: { target: 'priority', search_attr: @search_attr, order: 'desc' }
_search_form.html.haml
%div = form_tag(search_tasks_path, method: :get) do = label_tag :task_title, Task.human_attribute_name(:title) = text_field_tag 'task[title]', search_attr[:title] = label_tag :task_status, Task.human_attribute_name(:status) - statuses = Task.statuses_i18n.invert = select_tag 'task[status]', options_for_select(statuses, search_attr[:status]), prompt: '-' = submit_tag t('common.search')
_order_form.html.haml
= form_tag(search_tasks_path, method: :get, style: 'display: inline') do = hidden_field_tag 'task[title]', search_attr[:title] = hidden_field_tag 'task[status]', search_attr[:status] = hidden_field_tag "order[#{target}]", order = submit_tag order_icon(order) # asc: ▲、desc:▼
ちなみにdeadline DESC
等の文字列は、order_string
メソッドを使って生成するようにしてみました(・∀・)
task_controller.rb
class TasksController < ApplicationController def index prepare_search_attr @tasks = Task.all.order(order_string) end def search prepare_search_attr @tasks = Task.search(@search_attr).order(order_string) render :index end private def order_string return 'created_at DESC' unless params.key?(:order) order_params.to_h.map { |key, val| "#{key} #{val.upcase}" }.join(',') end def prepare_search_attr @search_attr = { title: '' } @search_attr = task_params.delete_if { |_key, val| val.blank? } if params.key?(:task) end def task_params params.require(:task).permit(:title, :description, :status, :priority, :deadline) end def order_params params.require(:order).permit(:deadline, :priority) end end
おわりに
今回はhidden_tag
を使って検索条件を引き継いでソートする方法で今回は対応してみました。やりたいことは出来ましたが、もっとRailsっぽい良い方法があるような気がしますね・・・!
なにかまたいい方法があればまとめてみようと思いますφ(..)