【Rails入門説明書】form_forについて解説

公開日: 2018.10.31
更新日: 2024.01.04
Railsのdeviseを用いてログイン認証を実装する方法を解説

form_forヘルパーを使うことで、フォームを簡単に設置することができます。
そのため、多くのRailsアプリケーションで使われています。

しかし、多くの人がform_forヘルパーがどんな動きでフォームを作っているのかをあまり理解しないままに使ってしまっています。
もし曖昧なまま使っているのであれば、ぜひこの記事を読んでみてください!

また、初めてform_forヘルパーを使ったViewファイルを見て、「よく分からない」という人はチャンスです!
これを機会に、理解しておくことをお勧めします。

form_forヘルパーは、Rails5.1から非推奨(将来的になくなる可能性がある)になりました。
Rails5.1以降にform_forヘルパーの代わりとなるform_withヘルパーについては、「【Rails入門説明書】form_withについて解説」を参照してください。
ただし、form_forヘルパーを理解してからの方が分かりやすいので、まずは本記事を読まれることをおすすめします。

form_forを読み解く

実際のプログラムコードを見ながら、form_forがどういった動きをしてフォームを作っているのかを解説していきます。

環境作成

scaffoldを使えば、簡単に具体例を作れますので、まずはテスト用の環境を作ります。コマンドプロンプトで以下のコマンドを順に実行してください。
※詳細は、「【Rails入門説明書】scaffoldについて解説」を確認してください。

コマンドプロンプト
$rails new form_test
$ cd form_test
$ rails generate scaffold User name:string age:integer email:string password:string note:text
$ rake db:migrate
$ rails c
 User.create(name:"Arioka", age:30, email:"dai@hese.jp", password:"0000", note:"member")
 User.create(name:"Yamada", age:28, email:"ryo@hese.jp", password:"1111", note:"top")
 exit

お使いのRailsバージョンが5.1以上の場合は、form_withメソッドが使われます。
そのため、Viewのフォームをしている_form.html.erbの1行目を修正しておいてください。
(app/views/users/_form.html.erb)

・変更前

html.erb
<%= form_with(model: user, local: true) do |form| %>

・変更後

html.erb
<%= form_for(user) do |form| %>

念のため、サーバーを起動し、ブラウザで「localhost:3000/users」にアクセスしてみましょう。

フォームの確認

まずは、scaffoldで作成したフォームapp/views/users/_form.html.erbを見てみましょう。

少し長いですが、プログラムコードと、生成されるHTMLの抜粋が以下です。
(app/views/users/_form.html.erb)

html.erb
<%= form_for(user) do |form| %>              <!-- (1) -->
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% user.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :name %>                  <!-- (2) -->
    <%= form.text_field :name %>             <!-- (3) -->
  </div>

  <div class="field">
    <%= form.label :age %>                   <!-- (2) -->
    <%= form.number_field :age %>            <!-- (4) -->
  </div>

  <div class="field">
    <%= form.label :email %>                 <!-- (2) -->
    <%= form.text_field :email %>            <!-- (5) -->
  </div>

  <div class="field">
    <%= form.label :password %>              <!-- (2) -->
    <%= form.text_field :password %>         <!-- (6) -->
  </div>

  <div class="field">
    <%= form.label :note %>                  <!-- (2) -->
    <%= form.text_area :note %>              <!-- (7) -->
  </div>

  <div class="actions">
    <%= form.submit %>                       <!-- (8) -->
  </div>
<% end %>

form_forヘルパーそのものは(1)の行で使われ、form_forヘルパーのブロック引数formが得られています。
このブロック引数formは、form_forヘルパーに渡されているモデルオブジェクトの情報を保持するFormBuilderオブジェクトです。

そして、FormBuilderオブジェクトのメソッドを使っているのが、(2)から(8)の部分です。この点を踏まえて、生成されるHTMLを見てみます。
(※FormBuilderはHelperを継承していますので、Helperのメソッドも使えます)

(新規作成画面で生成されるHTMLの抜粋)

html.erb
<span><form action="/users" method="post"></span>

  <div class="field">
    <label for="user_name">Name</label>                                                        <!-- (2) -->
    <input type="text" name="user[name]" id="user_name" />                                     <!-- (3) -->
  </div>

  <div class="field">
    <label for="user_age">Age</label>                                                          <!-- (2) -->
    <input type="number" name="user[age]" id="user_age" />                                     <!-- (4) -->
  </div>

  <div class="field">
    <label for="user_email">Email</label>                                                      <!-- (2) -->
    <input type="text" name="user[email]" id="user_email" />                                   <!-- (5) -->
  </div>

  <div class="field">
    <label for="user_password">Password</label>                                                <!-- (2) -->
    <input type="text" name="user[password]" id="user_password" />                             <!-- (6) -->
  </div>

  <div class="field">
    <label for="user_note">Note</label>                                                        <!-- (2) -->
    <textarea name="user[note]" id="user_note"></textarea>                                     <!-- (7) -->
  </div>

  <div class="actions">
    <input type="submit" name="commit" value="Create User" data-disable-with="Create User" />  <!-- (8) -->
  </div>
</form>

プログラムコードの(1)から(8)が、HTMLの(1)から(8)の部分に該当しています。

(1)の部分を比較すると、form_forヘルパーによってフォームが生成されています。
そして、(2)から(8)のFormBuilderオブジェクトのメソッドが、フォームの各部品(フォームコントロール)を生成しているわけです。

form_forが生成するフォーム

もう少し、form_forヘルパーがどうやってフォームを生成しているのか、プログラムコードと生成されるHTMLを並べて、確認してみましょう。
(app/views/users/_form.html.erb)

html.erb
<%= form_for(user) do |form| %>              <!-- (1) -->
html.erb
<span><form action="/users" method="post">     <!-- (1) --></span>

プログラムコードの「do |form|」については、ブロック指定ですのでここでは無視します。
すると、「form_for(user)」がここでのform_forヘルパーのコードということになります。

たったこれだけのコードだけで、適切なフォームが生成されます。
Railsの自動推測によって、form_forヘルパーに渡されたモデルオブジェクト(今回はuser)から、HTMLのactionとmethodの値を推測してくれているのです。

今回は新規作成であるため、userはnewされたばかりで、値が入っていません。
そのため、新規作成用のフォームが生成されています。

なお、編集画面の場合のHTMLは以下です。

html.erb
<span> 
<form action="/users/1" method="post">              <!-- (1) --></span>

プログラムコードは同じですが、userオブジェクトが値を持っているかどうかで、classやid、actionの値が適切に変わっています。

FormBuilderオブジェクトのメソッドが生成するフォームコントロール

次に、FormBuilderオブジェクトのメソッドがどんな解釈をされて、フォームコントロールが作られているのかを見ていきましょう。

(app/views/users/_form.html.erb)

html.erb
<%= form.label :name %>                <!-- (2) -->
    <%= form.text_field :name %>           <!-- (3) -->

html.erb
    <label for="user_name">Name</label>                                 <!-- (2) -->
    <input type="text" name="user[name]" id="user_name" />              <!-- (3) -->

(3)のテキストボックスについては、text_fieldメソッドが生成してくれます。

引数として渡しているシンボルから格納すべき値を推測しますが、このとき、メソッドを利用しているFormBuilderオブジェクトが保持しているモデルの情報に紐づけ、user[name]を格納先に指定してくれます。(idも同様)

ラベルについても同じく、labelメソッドの引数から関連付けるコントロールのidが推測されています。

なお、form_forヘルパーが生成したフォームで入力した値については、コントロールからparams[モデル名][カラム名]のハッシュ(ここでは、params[user][name])でアクセスすることができます。

山口さん インタビュー 非公開: 「人のために働きたい」を実現【警察官からエンジニア転職】

form_forの詳細情報

Railsの基本的な動き通り、form_forヘルパーもシンボル名などから推測して処理を追加してくれます。

とても便利ではあるのですが、それでは思ったような動きができないことがあります。そんな場合にカスタマイズできるオプション設定がありますので、form_forヘルパーの構文とともに紹介しましょう。

構文

ruby
$ form_for(モデルオブジェクト , オプション) do |f|
  フォームコントロールの設置
$ end

オプションには、以下があります。

オプション 説明 デフォルト
:url フォームの送信先 現在のURL
:namespace 名前空間の設定をしているコントローラへデータを渡したい場合の名前空間 名前空間なし
:method HTTPリクエスト POST
:authenticity_token クロスサイト・リクエストフォージェリ(CSRF)という脆弱性に対策するための認証トークンの無効化や変更 デフォルトトークン
:remote trueを指定すると、Unobtrusive JavaScript(控えめなJavaScript)で送信する情報を制御できる false(Ajaxでの送信)
:enforce_utf8 IE5以前のブラウザの文字化け対策用に埋め込むHiddenパラメータの出力設定
true:出力
false:出力しない
true
:html フォームコントロールにHTML属性をつける 属性なし
:as モデルの名称を一時的に設定する モデル名

テスト環境のform_forヘルパー(app/views/users/_form.html.erb)について、敢えてオプション設定を使って記載すると、以下のようになります。

html.erb
<%= form_for user, 
             as: :user,
             url: users_path,
             html: { class: "new_user", id: "new_user" } do |form| %>

userがnewしたばかりの場合、Railsは裏でこのような設定を行って処理しているのです。

参考として、編集の場合は、以下のようになるでしょう。

html.erb
<%= form_for user, 
             as: :user,
             url: user_path(user),
             method: :patch,
             html: { class: "edit_user", id: "edit_user_1" } do |form| %>

この形を憶えておくと、オプションによるカスタマイズがやりやすいかもしれません。

なおオプション設定の中で「:urlオプション」と「:namespaceオプション」、「:htmlオプション」の3つは比較的よく使いますので少し詳しく説明しておきましょう。

フォームで入力された情報の送信先を変える

「:url」オプションを使えば、入力データの送信先を変更できます。

例えば、新規登録画面で入力したデータで更新する場合のプログラムコードを紹介しましょう。(新規登録したデータが、登録済みの人の場合に、更新するといった場合に必要になるかもしれません)

form_forヘルパーに、以下のようにオプションを追加してみましょう。
(app/views/users/_form.html.erb)

html.erb
<!-- <%= @user = User.find(1) %> -->
<%= form_for(user, 
             url: user_path(@user),
             method: :patch,
             html: { class: "edit_user", id: "edit_user_1" }) do |form| %>  <!-- (1) -->

なお、上書きする既存のデータを指定するため、変数@userを追加しています。

「localhost:3000/users/new」にアクセスして[Create User]をクリックしてもデータは3つのままで、追加しようとした情報が1つ目のデータに上書きされます。

フォームにHTML属性をつける

フォームに自動で付与されるidやclassなどを変更したり、他のHTML属性をつけたりする場合に使うのが「:html」オプションです。

「:html」オプションに、ハッシュでHTML属性を渡すことで、フォームにHTML属性を設定することができます。

(app/views/users/_form.html.erb)

html.erb

html.erb
<%= form_for(user,
             html: { class: "test_form", id: "test_form" }) do |form| %>  <!-- (1) -- >

見た目は変わりませんが、HTMLは以下のようになっています。(抜粋です)

html.erb
<form class="test_form" id="test_form" action="/users" method="post">     <!-- (1) -->

別の名前空間のコントローラへフォームで入力された情報を送信する

例えば同じ商品テーブルからデータを表示する際、会員と非会員で画面を変えたい場合などは、それぞれ別のディレクトリを作って、コントローラもViewも別に管理した方が、メンテナンス性は高いでしょう。

そのような場合、ルーティングでディレクトリ名の名前空間を設定して対応します。
そうすることで、Railsがディレクトリを推測して、正しいコントロール(アクション)へアクセスするURLを生成してくれるのです。

DMMWEBCAMP 非公開: 未来を変えるワクワクした仕事に就きたい!経理業務からエンジニアへの転職エピソード

form_forが生成するフォームコントロール

form_forヘルパーのブロック引数として得られるFormBuilderオブジェクトのメソッドが、フォームコントロールを生成します。

このとき、メソッドによって生成されるフォームコントロールが違いますので、必要なメソッドを知らなければいけません。
ここでは、メソッドの種類と生成されるフォームコントロールについて、紹介しましょう。

メソッド 説明 オプション(入力対象カラムの後の引数)
check_box チェックボックス HTML属性を設定可能
color_field 色の入力欄 HTML属性を設定可能
date_field 日付の入力欄 デフォルト値とHTML属性を設定可能
datetime_field 日時の入力欄(グローバルタイム) HTML属性を設定可能
datetime_local_field 日時の入力欄(ローカルタイム) HTML属性を設定可能
email_field emailアドレスの入力欄 HTML属性を設定可能
fields_for form_forの中で別のモデルを指定したフォーム form_forと同じ
file_field 画像や文章などのファイルを選択するフォーム HTML属性を設定可能
hidden_field 隠しフィールドの生成 HTML属性を設定可能
label ラベルの生成 HTML属性を設定可能
month_field 月の入力欄 最小値(:min)、最大値(:max)、粒度(:max)、HTML属性を設定可能
粒度は、数字を増減させるためのボタンで増減される値
number_field 数値入力欄
数字以外は入力不可能
HTML属性を設定可能
password_field パスワード入力欄
入力された文字は自動的に*表示(マスク)される
HTML属性を設定可能
phone_field
telephone_field
電話番号入力欄 HTML属性を設定可能
radio_button ラジオボタンの生成 表示文言、チェックの有無(checked)、HTML属性を設定可能
range_field 範囲選択バー HTML属性を設定可能
search_field 検索ボックスフォーム HTML属性を設定可能
text_area 文字列入力欄
改行込みの文字列
HTML属性を設定可能
text_field 文字列入力欄 HTML属性を設定可能
time_field 時間入力欄 最小値(:min)、最大値(:max)、粒度(:max)、HTML属性を設定可能
粒度は、数字を増減させるためのボタンで増減される値
url_field URL入力欄 HTML属性を設定可能
week_field 週の入力欄 最小値(:min)、最大値(:max)、粒度(:max)、HTML属性を設定可能
粒度は、数字を増減させるためのボタンで増減される値
submit 送信ボタン 表示文言、HTML属性を設定可能
入力対象カラムは不要
表示文言を省略すると、モデルが保存済みかどうかで文言を変更する
(保存済み:「Update モデル名」 未保存:「Create モデル名」)

まとめ

form_forヘルパーについて、お伝えしました。

form_forヘルパーを利用すれば、ユーザー登録や編集などのフォームが手軽に実装でき、Viewファイルのプログラムコードもすっきりと分かりやすいものになります。

Railsの特徴である名称による推測でプログラムコードが自動生成されますので、URLの管理などもほとんど行う必要がなく、メンテナンス性も高いと言えるでしょう。

その反面自由度が低く、オプションを駆使してカスタマイズできなければ思ったような管理ができなくなりますので、しっかりと学習していきましょう。

ただし、冒頭にも書いたとおり、Rails5.1からはform_forは非推奨(将来的になくなる可能性がある)になりましたので、form_forヘルパーの代わりとなるform_withヘルパーについても、並行して学習を進めるようにしてください。

なお、form_withヘルパーについては、別の記事「【Rails入門説明書】form_withについて解説」で詳しく説明してますので、ぜひお読みください。



・form_forヘルパーで、フォームを簡単に設置できる
・form_forヘルパーで得られるFormBuilderオブジェクトのメソッドがフォームコントロールを生成する
・form_forヘルパーのオプションで、入力データの送信先を変更できる
・form_forヘルパーは、Rails5.1から非推奨(将来的になくなる可能性がある)になる。
・Rails5.1以降は、form_withヘルパーを使う

【インタビュー】1ヶ月でRubyをゼロから学び、Webエンジニアとして転職!

ブラジルから帰国し技術をつけようとRubyエンジニアを目指してWebCampでRubyを学び、見事Webエンジニアとして転職を果たした田中さんにお話を伺いました。

Rubyの学習がしたい。基礎をしっかりと理解したい

転職のサポートがほしい

と考えている方はぜひお読み下さい。

https://web-camp.io/magazine/archives/8535

関連記事

資料請求

  • 短期集中で最速エンジニア転職を実現-転職成功者インタビュー一覧

    DMM WEBCAMPでは転職成功率98%を実現しています。本資料では、元警察官や元ラーメン屋など様々なバックグラウンドを持つ卒業生の声をお届けします。

    資料をダウンロードする
  • IT技術がもたらす3つの変化と身につけるべきスキル

    IT技術の発展により、今後10~20年程度で47%の仕事がなくなると言われています。どのような変化が訪れ、私達はどのようなスキルを身につけるべきかを解説します。

    資料をダウンロードする
  • 未経験がフリーランスエンジニアになる方法-年収アップで自由な働き方を手に入れる

    働き方改革やリモートワークの影響でフリーランスという働き方の人気は高まりつつあります。フリーランスエンジニアとして活躍するために必要な情報をお届けします。

    資料をダウンロードする

© 2024 WEBCAMP MEDIA Powered by AFFINGER5