【Rails】Action View(ビュー)の書き方《フォーム篇》

はじめに

ActionView(ビュー)では、一般的なフォームを作成するための豊富なヘルパーメソッドが用意されています。Railsアプリにおいてフォームはなくてはならないものです。ユーザーの目に触れる部分でもあるので、フォームの良し悪しがアプリの評価にも繋がります。

本記事では、ActionView(ビュー)の機能のうち、フォームに関することをまとめています。

フォームの書き方

フォームのヘルパーメソッド

Rails 5まではフォームを設置するときにform_tag、あるいはform_forを使っていました。form_tagは関連するモデルがないときに使用し、form_forは関連するモデルがあるときに使用します。これらはフォームの中のフィールドの書き方にも差異があり、あまり使い勝手がいいとは言えませんでした。

Rails 5.1でform_withが追加されました。form_withは、それまでのform_tagform_forを統合したようなメソッドです。引数を指定することで、フォームとモデルの関連があるかないかをRailsに伝えます。

form_withの登場でform_tagform_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(ビュー)のフォームの使い方を覚えていただければと思います。

関連記事

【Rails】Railsアップグレードまとめ
# はじめに Ruby on Railsに限らず、何らかのフレームワークを使ってWebシステムを構築している場合、フレームワークのアップグレード作業は避けて通れません。 一般的にフレームワークはバージョン毎にEOL (End of Life [...]
2022年10月1日 14:32
【Rails】ユーザー登録時に行うメールアドレス認証機能の実装方法
# はじめに ユーザー登録/解除やログイン/ログアウトといった認証機能の導入に「devise」というGemを使っている人は多いと思います。「devise」では以下のように記述するだけで、ユーザー登録時に確認メールを送付しメールアドレス認証を行う機 [...]
2022年9月24日 14:24
【Rails】モデルに列挙型(enum)を定義し、使いこなす方法
# はじめに Railsはモデルでカラム名と同名の列挙型(enum)を定義することで、カラムと列挙型の変数を紐付けることができます。カラムと列挙型の変数を紐付けると、カラムに対して様々な便利な使い方ができるようになります。 本記事では、モデ [...]
2022年9月3日 10:29
【Rails】RailsでCORSとPreflight requestの設定を行う方法
# はじめに RailsアプリをAPIサーバーとして構築するには、CORS (Cross-Origin Resource Sharing)と Preflight requestの設定を行う必要があります。APIサーバーは外部からの要求に対して処理 [...]
2022年8月27日 10:44
【Ruby】Bundlerを使ってRubyGemsを作成/公開する方法
# はじめに Bundlerを使ってRubyGemsを作成および公開する方法について説明します。Bundlerを使わずにRubyGemsを作成/公開する方法については以下の記事を参照してください。 <iframe class="hatena [...]
2022年7月12日 23:18
【Ruby】RubyGemsを作成/公開する方法
# はじめに RubyGemsを作成および公開する方法について説明します。Bundlerを使ってRubyGemsを作成する方法については以下の記事を参照してください。 <iframe class="hatenablogcard" style [...]
2022年7月11日 21:52
【Rails】M1チップ搭載MacでRuby on Railsの開発環境構築
# はじめに M1チップ搭載MacにRuby on Railsの開発環境を構築する手順を記載します。 - MacBook Air (M1, 2020) - macOS Monterey 12.3.1 # Homebrew ## [...]
2022年5月5日 11:56
【Rails】Rakeタスクの基本情報と作成・実行方法
# はじめに Railsには標準でRakeというGemが同梱されています。RakeはRubyで実装されたMake(UNIX系のOSで使用できるコマンド)のようなビルド作業を自動化するツールです。Ruby Make、略してRakeというわけですね。 [...]
2022年3月7日 22:12