複数項目の検索フォームへのバリデーション


#1

Railsのきれいなコードのお題案 · Issue #1 · clean-rails-ja/conversationからの転載

複数の項目からなる検索フォームを実装するときに、検索フォームの各項目や項目間に対してvalidationを加えたいことがあります。例として楽天トラベルさんの検索フォームを出します。

2017-12-22 21 14 01

この例で言えば、「チェックアウト日」は「チェックイン日」よりも後とか「合計金額」の上限と下限の関係とかをチェックするような処理です。

個人的には、Form Objectを作ってそこでvalidationと検索処理を実装するのですが、検索処理の実装がごちゃごちゃになってしまいます。検索処理というとransack gemが有名なのですが、これもどうなのかなと思っている次第です。


#2

ものとしてはフォームオブジェクトと同じになる気がしますが、検索モデルを作ります。
検索モデルの各プロパティが入力項目に対応する感じですね。

当然各プロパティに対するヴァリデーションもこのモデル内に実装します。
単純な各プロパティ単体のものも、他のプロパティとの関係性のヴァリデーションも。
検索に関するビジネスロジックは結構長くなる傾向はあるかと思いますが、原則的にこのモデル内にすべて収めます。

ここまで書いた範囲ではフォームオブジェクトと実装上の違いがないように思いますが、あくまでビューを主体とした意識か、扱うリソースという考えでいるかの違いかなと思っています。
例えば標準検索と詳細検索のように、検索対象が共通なもののフォームが違う場合がありますが、この場合はフォームオブジェクトはあくまで検索フォームの表現とヴァリデーション、検索モデルは与えられたユーザ入力の検索パラメータのヴァリデーションと検索処理実行、という風に役割が分かれます。
検索モデルをサービスとして実装しても良いと思いますが、このあたりは好き好きかもしれません。

ransackはどちらの構成でも使えるような気がしますが、基本的に使いません。


#3

このトピックはFormオブジェクトと検索モデルでファイナルアンサーですかね。

ransackは嫌いな人が多くいるのは知っているけど、個人的には便利に使うことが多いです。簡単なモデルの検索であれば実装がめっちゃ楽になるので使ってしまいますね…。複雑なやつ(全文検索が必要とか)はそもそもransackでは実現できないので専用のオブジェクトを作るしかないですね。