はじめに
ActionView(ビュー)では、一般的なフォームを作成するための豊富なヘルパーメソッドが用意されています。Railsアプリにおいてフォームはなくてはならないものです。ユーザーの目に触れる部分でもあるので、フォームの良し悪しがアプリの評価にも繋がります。
本記事では、ActionView(ビュー)の機能のうち、フォームに関することをまとめています。
フォームの書き方
フォームのヘルパーメソッド
Rails 5まではフォームを設置するときにform_tag
、あるいはform_for
を使っていました。form_tag
は関連するモデルがないときに使用し、form_for
は関連するモデルがあるときに使用します。これらはフォームの中のフィールドの書き方にも差異があり、あまり使い勝手がいいとは言えませんでした。
Rails 5.1でform_with
が追加されました。form_with
は、それまでのform_tag
とform_for
を統合したようなメソッドです。引数を指定することで、フォームとモデルの関連があるかないかをRailsに伝えます。
form_with
の登場でform_tag
とform_for
の仕様は非推奨となりました。ここでは、form_with
の使い方について記述します。
form_withの書き方
form_with
は関連するモデルの有無で書き方が変わります。関連するモデルがない場合の書き方は以下の通りです。
<%= form_with url: '/search' do |form| %>
<%= form.text_field :search_text %>
<%= form.submit %>
<% end %>
関連するモデルがある場合の書き方は以下の通りです。
<%= form_with model: @article do |form| %>
<%= form.label :title %>
<%= form.text_field :title, placeholder: '題名' %>
<%= form.label :content %>
<%= form.text_area :content, placeholder: '本文', rows: '10' %>
<%= form.submit %>
<% end %>
form_with
の第1引数がurl
なら関連するモデルがない、model
なら関連するモデルがあるということになります。フォームの中のフィールドの書き方に差異はありません。
form_withのレコード識別
form_with
にモデルのインスタンスを渡すと、モデルの中身にあわせて適切なフォームを構築します。モデルのインスタンスからモデル名のハッシュを作成し、コントローラーに送信します。コントローラーではフォームに入力された値をparams[:article][:title]
のように取得することができます。
モデルのインスタンスが空の場合、フォームのメソッドをPOST
にし、適切なルーティングを設定します。また、モデルのインスタンスが空でない場合、フォームのメソッドをPATCH
にし、適切なルーティングを設定します。そして各フィールドにインスタンスの各値を設定します。
これにより、フォームを作成画面と編集画面で分けて作成する必要がなくなり、共通のパーシャルとしてテンプレートに組み込むことができるようになります。パーシャルについては以下の記事を参照してください。
form_withの同期通信
form_with
はデフォルトで非同期通信を行います。従来どおり同期通信にしたい場合は、以下のようにlocal
引数を有効にします。
<%= form_with model: @article, local: true do |form| %>
...
<% end %>
フィールドのヘルパーメソッド
フォームには豊富なフィールドのヘルパーメソッドが用意されています。ここでは、よく使うフィールドの一部を紹介します。すべてのフィールドのヘルパーメソッドを確認したい場合や、フィールドのオプションをすべて確認したい場合は以下を参照してください。
フィールドの第1引数には属性名を指定します。関連モデルのあるフォームの場合、属性名はカラム名と言い換えても構いません。
label
label
はフィールドのラベルを作成します。label
単体で使うことはなく、必ず他のフィールドとセットで使います。label
の属性名は、セットとなるフィールドの属性名と一致させる必要があります。ラベル内容を省略すると属性名(頭文字は大文字)が使用されます。
<%= form.label :name, '名前' %>
<%= form.text_field :name %>
text_field
text_field
は通常のテキストボックスを作成します。maxlength
オプションで入力できる文字数を制限したり、プレースホルダーを設定できます。
<%= form.text_field :name, maxlength: 10, placeholder: '名前' %>
パスワードの入力にはpassword_field
、メールアドレスの入力にはemail_field
を使います。
<%= form.password_field :password, placeholder: 'パスワード' %>
<%= form.email_field :email, placeholder: 'メールアドレス' %>
email_field
に入力された値は、送信時にブラウザによりフォーマットチェックが行われます(以下はGoogle Chromeの例)。
check_box
check_box
はチェックボックスを作成します。チェックボックスとラベルを横並びにするには、以下のようにlabel
ブロックで囲む必要があります。
<%= field_set_tag '好きな動物は?' do %>
<%= form.label :check_dog do %>
<%= form.check_box :check_dog, checked: true %>
犬
<% end %>
<%= form.label :check_cat do %>
<%= form.check_box :check_cat %>
猫
<% end %>
<% end %>
radio_button
radio_button
はラジオボタンを作成します。ラジオボタンとラベルを横並びにするには、以下のようにlabel
ブロックで囲む必要があります。
<%= field_set_tag '同意しますか?' do %>
<%= form.label :agree, value: 'yes' do %>
<%= form.radio_button :agree, 'yes', checked: true %>
はい
<% end %>
<%= form.label :agree, value: 'no' do %>
<%= form.radio_button :agree, 'no' %>
いいえ
<% end %>
<% end %>
select
select
またはcollection_select
はセレクトボックスを作成します。セレクトボックスのリストにモデルのレコードを使う場合、collection_select
を使います。
<%= form.collection_select :animals, @animals, :id, :name, prompt: "選択してください", selected: @animal.id %>
各引数は以下の通りです。
引数 | 説明 | 設定例 |
---|---|---|
属性名 | フィールドの属性名。 | :animals |
コレクション | リストを含むモデルのインスタンス。 | @animals |
コレクションのキー | リストのキーとなるカラム名。 | :id |
コレクションの値 | リストの値となるカラム名。 | :name |
プロンプト | リストの先頭に表示する文字列。 | "選択してください" |
初期値 | リストの初期選択値。 | @animal.id |
セレクトボックスのリストにenum
の値を使う場合、select
を使います。
<%= form.select :animals, Animal.names.map { |k, v| [v, k] }, prompt: "選択してください", selected: @animal.id %>
各引数は以下の通りです。
引数 | 説明 | 設定例 |
---|---|---|
属性名 | フィールドの属性名。 | :animals |
コレクション | リストを含むenum 変数(複数形)のマッピング。 |
Animal.names.map |
コレクションのキーと値 | リストのキーと値の組み合わせ。 | { |k, v| [v, k] } |
プロンプト | リストの先頭に表示する文字列。 | "選択してください" |
初期値 | リストの初期選択値。 | @animal.id |
file_field
file_field
はファイル選択を作成します。file_field
を含むフォームはmultipart
を有効にする必要があります。
<%= form_with model: @article, multipart: true do |form| %>
<%= form.file_field :image %>
<% end %>
他のフィールドと違い、file_field
は初期値の設定ができません。例えば、@article.image
が設定されていたとしても、その値はfile_field
に設定されません。これは、セキュリティ上の問題で<input type="file">
タグには外部からアクセスできないためです。
編集画面などで@article.image
の中身を確認したい場合、以下のようにサムネイル表示しておくといいです。
<%= image_tag @article.image_url(:thumb) %>
<%= form.file_field :image %>
実際にファイルアップロードを行うには、ActiveStorageの設定やCarrierWave
の導入を行っておく必要があります。
フォームのエラー表示
モデルにバリデーションを設定しているとコントローラーでバリデーションチェックが行われ、結果が不適合だった場合はビューにエラーが返されます。
エラーメッセージはモデルのインスタンスの中のerrors
ハッシュに自動で格納されます。フォームの最上部などにエラーメッセージを表示する処理を記述しておきます。以下の例では、何かしらのエラーがあった場合、エラーメッセージをリスト形式で表示しています。
<% if @article.errors.any? %>
<h2>入力した値にエラーがあります。エラーを修正してください。</h2>
<ul>
<% @article.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
エラーメッセージをエラーのあるフィールドの近くに表示するには、以下のように記述します。
<%= form.text_field :title %>
<% if @article.errors.include?(:title) %>
<p class="error_message">
<%= @article.errors.full_messages_for(:title).first %>
</p>
<% end %>
また、バリデーションチェックの結果が不適合だったフィールドを囲むfield_with_errors
クラスが自動で追加されます。これによりデザインが崩れるという場合は以下のスタイルを追加します。
.field_with_errors {
display: contents;
}
なお、エラーメッセージを日本語化するには以下を参照してください。
まとめ
Railsのフォームタグヘルパーは、渡されたモデルのインスタンスを解析し、作成画面または編集画面のフォームを適切な形で構築してくれます。少ない記述で多くのことを自動でしてくれるため非常に使い勝手のいいメソッドなのですが、デフォルトの設定値などを把握しておかないと、思わぬ挙動を起こす可能性があります。
本記事を参考にして、ActionView(ビュー)のフォームの使い方を覚えていただければと思います。