Redmine 4.0(Rails 5.1)でのプラグイン作成について(3) - torutkのブログの続きです。
用語一覧表示において、べたに一覧表示する方法と、カテゴリ毎に一覧表示する方法とをラジオボタンで切り替える機能をどのように実装すればよいかを探っています。
アプローチの模索
スタンドアロン(デスクトップ)アプリケーションと違って、Webアプリケーションはサーバー側で表示(HTML)を生成するので、表示設定の変更もいったんサーバーに送って新たに表示を生成することになります。
JavaScriptで表示を制御するとしたら
JavaScriptを駆使して、ブラウザ上で表示を変更することもできないかとアプローチしてみましたが、表示する可能性のあるHTML要素を予め生成しておき、JavaScriptからHTML要素の表示有無を切り替えるといった振る舞いとなり、今回であればべた一覧表示とカテゴリ毎の一覧を両方生成し、どちらを表示するかを切り替えるといった実装になりそうです。
ラジオボタンのコールバックにJavaScriptの関数を指定し、ラジオボタンが押されたら、対応するHTML要素を有効化し、残りを無効化するようなイメージです。
べた一覧表示を、
ちょっと力業過ぎるかと思い、実装には入りませんでした。
フォームで制御するとしたら
ラジオボタンの設定をフォームでサーバーにサブミットし、サーバー側で設定を見てべた一覧表示かカテゴリ毎の一覧表示かを判別してHTMLを生成します。
ここで、Ruby on Rails では通常はモデルクラスを用意し、フォームではそのモデルのインスタンスを指定しインスタンスの属性を新規作成ならcreate、既存の変更ならeditアクションを実行します。
しかし、今回は表示設定なのでモデルクラスはありません。表示設定をデータベース化するならモデルクラスからコントローラークラス、ビューとフルに作ってもよいですが、そこまで頑張らずに済む方法を追求します。
用語コントローラーのindexアクションで、ラジオボタンの設定をリクエストパラメーターに持たせ、indexの描画時にパラメーターに応じてべた一覧表示かカテゴリ毎に一覧表示かを切り替えることとします。
まず、Redmine(Ruby on Rails)でフォームを実装するAPIとして利用できそうなものを探したところ次が見つかりました。
API | 内容 |
---|---|
form_for | モデルインスタンス用のフォーム |
form_tag | カスタムURL(モデルインスタンス不要)用のフォーム |
form_with | Ruby on Rails 5.1から導入され、form_forとform_tagの両者の機能を持ち将来的に置き換わるAPI |
labelled_form_for | Redmineが提供するform_forのラッパー |
今回はモデルクラスとモデルインスタンスを指定せずにフォームを実現したいので、モデルの指定が不要なform_tagまたはform_withを使用します。
form_withについては、従来のform_forとform_tagの機能を兼ね備え、これらを代替するものとしてRails 5.1で導入されました。将来的にはform_forとform_tagはデプリケートとなる予定です(Rails 6あたり)。
form_tagでラジオボタンを設置
書式は、
form_tag(URL [, options]) do end
といった感じです。
用語一覧のコントローラーのindexアクションはルーティング設定でproject_glossary_termsの末尾に_pathを付けたものになります。
メソッドはデフォルトではpostになってしまうので、明示的にgetを指定しています。
<%= form_tag(project_glossary_terms_path, method: :get) do %> <%= radio_button_tag :grouping, 1, @grouping == '1' ? true : false %> <%= label_tag 'カテゴリで分類' %> <%= radio_button_tag :grouping, 0, @grouping == '0' ? true : false %> <%= label_tag '分類なし' %> <%= submit_tag '表示' %> <% end %>
ラベルの指定は不十分かもしれません(ラジオボタンと紐づくラベルを生成するにはさらなる指定が必要な模様)。
form_tagを使用する場合、radio_buttonではなくradio_button_tagを使用するようです。
form_with
これは、用語集プラグイン再構築で実装したので日記では省略します。