Railsでフォームを作る際にform_for
を使うとページの再描画が発生しても入力値がリセットされませんが、form_tag
を使うとリセットされてしまいます。。。
検索フォーム等では、form_tag
を使用することが多いような気がするのですが、検索ボタンを押してもリセットされずに残ってほしいなー!と思い対応してみたので、その方法をメモしておきますφ(..)
入力値がリセットされない検索フォームの作り方メモ
今回は、index
アクションでは全件取得、search
アクションでは検索条件に合致したレコードを取得して、最終的に共通なViewを描画するようなケースを想定してます。
Controller側
controller側のポイントは、prepare_search_attr
です。
index
の場合はパラメーターが無いケースがあるので、検索条件を保持するインスタンス変数@search_attr
に初期値を入れておき、検索条件が設定されていた場合は、それを上書きするようにしています。
controller
class TasksController < ApplicationController def index prepare_search_attr @tasks = Task.all end def search prepare_search_attr @tasks = Task.search(@search_attr) render :index end private def prepare_search_attr @search_attr = { title: '', status: '' } @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 end
View側
view側のポイントは_search_form.html.haml
のtext_field_tag
、select_tag
を記載しているところです。
text_field_tag
は第二引数に渡された値が初期値として設定され、select_tag
のoptions_for_select
の第二引数に渡された値が初期値として設定されます。
そのため、controller
側で定義しておいた@search_attr
を、渡して初期値を設定することが出来ます。
index.html.haml
%h1= t '.title' = render partial: 'search_form', locals: { search_attr: @search_attr } %br %table{ border: 1 } %thead %tr %th= Task.human_attribute_name(:title) %th= Task.human_attribute_name(:status) %th= Task.human_attribute_name(:priority) %th= Task.human_attribute_name(:deadline) %th Actions
_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')
おわりに
Railsの検索フォームの作り方は、毎度悩んでこれで良いのかなぁ感が大きいですね・・・(._.)もっと良い作り方等があれば、教えてください!!🙌
またコードの全文は万葉さんの公開している新人研修をやっている私のリポジトリにあるので見てアドバイスもらえるとありがたいですm( )m