Rails search_form_forの中で複数個submitボタンを用意し検索対象を絞る

開発現場でRailsを利用しています。

検索機能にはransacを利用しており、ある時search_form_forの中で、検索対象を切り分ける場面がありました。

何日か考えてしまったので、備忘録として残しておこうと思います。

具体的な要件のイメージ

  • 関東ボタンを押す → 案件一覧ページに関東に紐付いた案件が全部表示される

  • 関西ボタンを押す → 案件一覧ページに関西に紐付いた案件が全部表示される

  • 九州ボタンを押す → 案件一覧ページに九州に紐付いた案件が全部表示される

困っていたこと

  1. search_form_forの中でf.submitって複数個使えるの?
  2. viewからcontrollerに対して値(フラグとかパラメーターとか)を飛ばすことは可能?
  3. JS使わないとできないのかな?

解決方法(実装概要)

  1. HTMLのname属性を利用する。
  2. コントローラーで対象のname属性を受け取り条件分岐を使い処理を行う。

具体的にどうやったの(実際のコード)

  • HTML
<input type="submit" name="area_kanto" value="関東" >
<input type="submit" name="area_kansai" value="関西">
<input type="submit" name="area_kyusyu" value="九州">
  • View側(Slimです。BootStrap使っています。)
.flex-column
  h5.font-weight-bold.my-3.pl-2 エリアで絞る
    .search-area.d-flex.justify-content-around
      = f.submit '関東', name: 'area_kanto'
      = f.submit '関西', name: 'area_kansai'
      = f.submit '九州', name: 'area_kyusyu'
  • Contoroller側
if params[:area_kanto]
  area_kanto_array = Area.where_area_kanto.concat(params[:q][:area_id_in])
  params[:q][:area_id_in] = area_kanto_array
end

if params[:area_kansai]
  area_kansai_array = Area.where_area_kansai.concat(params[:q][:area_id_in])
  params[:q][:area_id_in] = area_kansai_array
end

if params[:area_kyusyu]
  area_kyusyu_array = Area.where_area_kyusyu.concat(params[:q][:area_id_in])
  params[:q][:area_id_in] = area_kyusyu_array
end

Area.where_area_kanto
Area.where_area_kansai
Area.where_area_kyusyu
はAreaモデルに記載したScopeの呼び出しです。それをransacの検索条件にconcatで配列結合しています。
ここらへんはこの記事とは関係ないです。

学び

HTMLのname属性使えばparams[:属性名]で検知できるんだ〜ってことでした。

Webの基本知識

HTTPってなに?①

  1. TCP/IPを基盤にしたプロトコル
  2. ステートレスなプロトコル

ステートレスな通信とはなにか

 「サーバーがクライアントのアプリケーション状態を保存しない」制約のこと。

 

ステートフルとは?

やり取りが簡潔であること。

ステートフルなやり取りでは、サーバー(店員)がクライアント(客)のそれまでの情報(注文)を覚えており、同じ情報を繰り返しはしない。

 

ステートレスとは?

やり取りが冗長であること。

ステートレスなやり取りでは、サーバー(店員)がクライアント(客)の情報(注文)を毎回繰り返す。

 

アプリケーション状態とはなにか

 サーバー(店員)がクライアント(客)の行ったことを記憶している状態のこと。

「クライアントのアプリケーション状態」と呼ぶ。

以下で居酒屋での注文シーンを想像してみる。

 

客:注文お願いします!

店員:どうぞ!

客:生中2つと枝豆1つお願いします。

店員:生中2つと枝豆1つですね。

客:あ、あとたこやきも1つ追加でお願いします。

店員:たこ焼き1つ追加ですね。以上でよろしいですか?

客:あーあと、冷やしトマトも1つ追加でお願いします。

店員:冷やしトマト1つですね、以上でよろしいですか?

客:はい。お願いします。

店員:ありがとうございます。ご注文承りました。

 

上記のように、一連の流れの中で店員は客からの注文を記憶し、オーダーをさばく。

この一連のやり取りをアプリケーション状態と呼ぶ。

また、アプリケーション状態は別名で「セッション状態」とも呼ばれ、ログインしてから(注文開始)ログアウトする(注文完了)までの状態のことを「セッション」と呼ぶ。

ちなみにこの居酒屋の店員さんはステートフルなやり取りを行っている。ステートフルなやり取りはステートレスなやり取りに比べて、無駄なやり取りがなく注文がスピーディーに行なえるため、早く食事をしたいクライアント(自分)としてはありがたい。しかし欠点も存在する。

ステートフルの欠点

サーバーがクライアントのアプリケーション状態(セッション状態)を覚えておくことは、クライアントが増えるにつれて難しくなってくる。

先程の居酒屋の例で例えると、5~6人ほどしか入らない小さな店では客が何を注文したかを覚えていられるが、100人以上入る大型店では、個別個別に注文をされても覚えきれない。

この問題を解決するのがステートレスアーキテクチャである。

ステートレスの利点

ステートレスではクライアントがリクエストメッセージ(注文)にすべての情報を詰め込み注文を行う。

居酒屋の例で考えてみる

 

客:注文お願いします!

店員:どうぞ!

客:生中2つと枝豆1つお願いします。あ、あとたこ焼き1つと冷やしトマト1つお願いします。

店員:ご注文以上ですか?

客:はい。お願いします。

店員:ご注文承りました。

 

ステートレスな状態ではサーバーがクライアントのセッション状態をすべて覚える代わりに、クライアントが自分のセッション状態を覚え、すべてのリクエストを自己記述的メッセージ(注文に含まれる必要な情報すべて)で送信する。そのためサーバーはセッション情報を覚える必要がなく、注文にさえ集中すれば良くなる。

そのため、ステートレスなシステムをスケールさせることも容易になる。(注文さえ正確に受けてくれる店員さんやロボットを増員すれば、大型店であっても店を回せる。)

ステートレスの欠点

パフォーマンスの低下

サーバーをステートレスにするためには、クライアントが毎度、自己記述的メッセージを送信する必要があり、データ量によってネットワークの帯域を消費する可能性がある。また認証ユーザー情報やパスワードがDB内に保存されている場合などは、認証を行うたびにDBへのアクセスが必要となるため、サーバーに負荷がかかる処理を繰り返すことになる。

 通信エラーへの対処が不十分

ステートレスなサーバーは注文を正確に受ける以上の仕事をしない。

重複した注文があった場合、ステートフルなサーバーは重複した注文があることをクライアントに知らせる事もできる。しかしステートレスなサーバーは都度、客に確認をすることなく注文を受けるため、クライアントが意図していない状況になる。

 

 

Webを支える技術を参考にさせていただいています

gihyo.jp