こんにちは、エンジニアのさもです。
仕事で1つのフォームに複数のボタンをつける実装があったので、そのような場合の対応方法を紹介します。
先に結論だけいうと、サブミットボタンを押したときに、フォームの送り先とメソッドを変えるようにしました。
目次
はじめに
まず経緯をお話しすると、
すでにあった画面の改修を行っていました。
その画面は、ユーザの一覧画面で、上部に検索用のフォームがあり、下部にはユーザに対して一括で値を入力し、更新できる一覧兼フォームという構成になっていました。
こんな感じです
<form ユーザ検索、method: get> 名前などの入力フィールド サブミットボタン </form> <form ユーザ更新 method: post> 選択的に更新するためのチェックボックス 更新対象カラムのフィールド サブミットボタン </form>
スポンサーリンク
さて、こんな構成の画面に対して、「検索したときに、一覧部分で入力したチェックボックスや値を保持して欲しい」という要望が入ったのです。
いくつか方法は考えられます
- javascriptで入力フォームの内容をコピーして、検索時に一緒に送る
- フォームを1つにまとめて、ボタンを押したときに送り先を変える
など
今回は2つ目の「フォームを1つにまとめて、ボタンを押したときに送り先を変える」で実装を行いました。
実装
view
まずは検索用フォームの中身を、一覧用フォームの中に入れます
<form ユーザ更新 method: post> 名前などの入力フィールド 検索サブミットボタン 選択的に更新するためのチェックボックス 更新対象カラムのフィールド 更新サブミットボタン </form>
このままでは検索ボタンを押すと更新されてしまうので、フォームの行き先とメソッドを変えます
<button class="search" onclick="$('form').attr('action', '<%= users_path %>');$('form').attr('method', 'get');">検索</button>
actionはフォームのURLに相当し、methodは送るときのメソッドです。
これで、ボタンを押したときにフォームの送り先が変わり、メソッドも変えてくれます。ついでに更新用フォームの中身も持っていってくれます。
controller
ついでにコントローラ側の実装もご紹介します。
更新フォームの検索ボタンを押すと、コントローラ側では検索用のアクションが呼ばれるようにしました。
今度は送られてきた値を画面に表示しなくてはなりません。
そこで、新しくインスタンス変数を用意しておきます。この変数はハッシュで、ユーザのidでアクセスすると、そのユーザへ入力した値を取り出せるようにしておきます。
送られてくるパラメータは例えば、以下のような形のものを想定します
params[:user_attributes] #=> {"1" => {"id" => "1", "name" => "new_name"}, "2" => {"id" => 4}, "3" => {"id" => 5, "age" => 30}}
画面側で入力値を再現するための変数を作ります
@user_attrs = {} params[:user_attributes].values.map{|v| @user_attrs["#{v['id']}"] = { name: v["name"], age: v["age"] } }
画面側のテキストフィールドのvalueをvalue: @user_attrs["#{user.id}"][:name]
などとすれば値が再現できます
最後に
まだプログラミング経験が浅いときに、同じように1つのフォームに複数のサブミットがある画面をつくっとことがあるのですが、そのときはフラグを持たせて、コントローラ側で振り分けていました。
今回の実装がベストではないかも知れませんが、昔の実装よりはよくなったと思います!
1つのフォームに複数のボタンという構成は少なくないと思うので、困っている新人エンジニアの方の参考になればと思います。
読者登録をしていただけると、ブログを続ける励みになりますので、よろしくお願いします。