ブンバボーンな毎日

RubyやPython, JavaScriptなど勉強したことなど、IT関連の記事を書いています

railsでフォームに複数のサブミットボタンをつける

f:id:s-uotani-zetakansu:20170823234714j:plain

こんにちは、エンジニアのさもです。

仕事で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"] } }

画面側のテキストフィールドのvaluevalue: @user_attrs["#{user.id}"][:name]などとすれば値が再現できます

最後に

まだプログラミング経験が浅いときに、同じように1つのフォームに複数のサブミットがある画面をつくっとことがあるのですが、そのときはフラグを持たせて、コントローラ側で振り分けていました。

今回の実装がベストではないかも知れませんが、昔の実装よりはよくなったと思います!

1つのフォームに複数のボタンという構成は少なくないと思うので、困っている新人エンジニアの方の参考になればと思います。

読者登録をしていただけると、ブログを続ける励みになりますので、よろしくお願いします。