【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】Paranoiaを使用した論理削除(ソフトデリート)
# はじめに Paranoiaは、Railsアプリケーションで論理削除(ソフトデリート)を実現するためのGemです。 論理削除は、データベースのレコードを物理的に削除するのではなく、削除フラグを設定することで「削除済み」とみなす方法です。こ [...]
2024年7月20日 21:33
【Rails】activerecord-multi-tenantを使用したマルチテナントアプリケーションの作成
# はじめに マルチテナントアプリケーションでは、複数の顧客(テナント)が同じアプリケーションを利用するため、データの分離が必要です。 activerecord-multi-tenantは、このようなマルチテナント環境をサポートするための便 [...]
2024年7月18日 16:50
【Rails】RubyとRailsにおけるattr_reader, attr_writer, attr_accessorの概念と使用方法
# はじめに RubyとRailsの開発において、`attr_reader`,`attr_writer`,`attr_accessor`は非常に便利なメソッドです。これらは、クラス内でインスタンス変数に対するゲッターおよびセッターメソッドを簡単に [...]
2024年7月17日 18:11
【Rails】RubyとRailsにおけるyieldの概念と使用方法
# はじめに RubyとRailsにおける`yield`は、メソッドやテンプレートの中で動的にコードブロックを実行する能力を提供し、これによってコードの再利用性と拡張性が大幅に向上します。本記事では、RubyとRailsにおける`yield`の概 [...]
2024年7月17日 13:15
【Rails】AASMを使用してオブジェクトの状態遷移を効率的に管理
# はじめに Railsアプリケーションにおいて、オブジェクトの状態管理は重要な課題の一つです。AASM (Acts As State Machine) gemは、複雑な状態遷移を効率的に管理します。本記事では、AASMの基本的な使い方を解説して [...]
2024年7月16日 18:00
【Rails】RSpec + Swagger + rswagでアプリケーションのAPIをテストおよびドキュメント化する方法
# はじめに Railsアプリケーションの開発において、APIのテストとドキュメント化は重要な要素です。 RSpecはテストフレームワークとして広く利用されており、SwaggerはAPIの設計とドキュメント化を支援します。これらを統合するr [...]
2024年7月16日 14:27
【Rails】mailcatcherを使用して開発環境でメール送信をテストする方法
# はじめに mailcatcherは、開発環境でのメール送信をキャプチャするためのツールです。ローカルで送信されたメールをブラウザ上で簡単に確認できるようにします。mailcatcherをRailsアプリケーションで使用する方法について説明しま [...]
2024年7月15日 16:37
【Rails】impressionistを使用してページビューやクリック数を追跡する方法
# はじめに impressionist Gemを使用してRailsアプリケーションでページビューやクリック数を追跡する方法について説明します。 # 実装方法 ## impressionist Gemのインストール まず、impre [...]
2024年7月15日 14:18