【Rails】form_forの使い方を徹底解説!

Rails

form_forとは

railsで情報を送信するためのヘルパーメソッドです。
form_forを使うことにより、簡単に入力フォームに必要なHTMLを作成することができます。
主にテーブルにレコードを新規作成、更新するときに利用します。

form系ヘルパーメソッドの使い分け
リンクをコピーしました

railsで投稿フォームを作成するにはセキュリティの面から直接inputタグを利用して書くことはありません。
投稿フォームを作成するにはform_tagやform_for、form_withといったヘルパーメソッドを使用します。

投稿フォームに投稿された内容を保存するテーブルが存在するときにはform_forを使います。
それに対し検索フォームのようなフォームは検索ワードを入力してもらうだけでそのワードはデータベースに保存する必要はないですよね?
そういう場合のフォームはform_tagで作成します。

form_withはrails5から使えるようになったヘルパーメソッドで、保存する内容がない場合でもform_forと同じようなコードで書くことができます。
rails5.1からはform_withを使うことが推奨されています。

form_forの使い方
リンクをコピーしました

ではform_forは実際どのように書くのかを見ていきましょう。

erb
1
2
3
<%= form_for('モデルクラスのインスタンス') do |f| %>
  フォーム内容
<% end %>

実際の例は下記のようになります。

erb
1
2
3
4
<%= form_for(@user) do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

上のコードはコンパイルされると下記のコードになります。

html
1
2
3
4
5
6
<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="✓" />
  <input type="hidden" name="authenticity_token" value="※ここにはトークンが入ります" />
  <input type="text" name="user[text]" id="user_text" />
  <input type="submit" name="commit" value="Create User" />
</form>

このようにform_forでフォームを作成すると、文字コードや不正な情報が投稿されないようトークンも自動で作成されます。
コードが非常に短くかけますし、セキュリティも高まるのでrailsでフォームを作成する際はform系のヘルパーメソッドを使って作成します。

form_forの引数
リンクをコピーしました

form_forの引数にはモデルクラスのインスタンスを指定します。
※()は省略可能です。
モデルクラスのインスタンスとは保存したいテーブルのクラスのインスタンスのことです。
今回はusersテーブルに新たにレコードを作成したいので、コントローラー側で下記のように記述します。

コントローラー
1
2
3
def new
  @user = User.new
end

この「@user」をform_forの引数に指定するわけです。

form_tagでは送信先に当たるパスを引数で設定しましたが、form_forでは記述がないことがわかります。
ではform_forではどのように送信先を決めているのでしょうか?
コントローラーで作成したインスタンスがnewメソッドで新たに作成されて何も情報を持っていなければ自動的にcreateアクションへ、findメソッドなどで作成され、すでに情報を持っている場合はupdateアクションへ自動的に振り分けてくれます。

コントローラー
1
2
3
4
5
6
7
8
9
def new
  @user = User.new
end
# 新規に作成したレコードなのでcreateアクションが動く

def edit
  @user = User.find(params[:id])
end
# 既存のレコードを取得しているのでupdateアクションが動く

なのでform_tagのようにパスとhttpメソッドを指定しなくても自動で振り分けてくれるというわけです。
非常に便利ですね!

ネストをしている時の書き方
リンクをコピーしました

ルーティングでネストを定義している時は記述が変わります。
記事に関するコメントを投稿するフォームを例に挙げてみます。
ルーティングは下記のようにしています。

routes.rb
1
2
3
resources :articles do
    resources :comments
end

まずはコントローラーのインタンス変数の定義です。

コントローラー
1
2
3
4
def new
  @article = Article.find(params[:article_id])
  @comment = Comment.new
end

コメントは必ずいずれかの記事に紐づいているので、どの記事のコメントなのかという情報が必要になります。
ですので「@article = Article.find(params[:article_id])」でコメントする記事を取得しています。
ビュー側は下記のように引数に配列を渡す形になります。

erb
1
2
3
4
<%= form_for [@article, @comment] do |f| %>
  <%= f.text_field :text %>
  <%= f.submit %>
<% end %>

コンパイルされると下記のようなコードになります。

html
1
2
3
4
5
# create時の例
<form class="new_comment" id="new_comment" action="/articles/1/comments" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" />

# update時の例
<form class="edit_comment" id="edit_comment_1" action="/articles/1/comments/1" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="_method" value="patch" />

html属性の付け方
リンクをコピーしました

下記のように記述するとフォームにhtml属性を付けることができます。

erb
1
<%= form_for @user , html: {属性: ‘属性値'} do |f| %>

例えばidに「new_form」と付けたいときは下記のように記述します。

erb
1
<%= form_for @user, html: {id: 'new_form'} do |f| %>

アクション名で記述してみよう
リンクをコピーしました

form_forはパスとhttpメソッドで次に動かすアクションを指定しなくても良いと書きましたが、ルーティングがうまくいかない時などは直接コントローラー名とアクション名を指定することもできます。

erb
1
2
3
4
<%= form_for(@user, url: {controller: 'users', action: 'index' }) do |f| %>
  <%= f.text_field :text %>
  <%= f.submit %>
<% end %>

form_tagとのparamsの構造の違い
リンクをコピーしました

form_tagで作成されたフォームのパラメータはparamsを使えば取り出すことができました。

ターミナル
1
2
3
# 例:form_tagの場合
params
=> {"name"=>"テスト太郎"}

ですがform_forで作成した場合は下記のようになります。

ターミナル
1
2
3
# 例:form_forの場合
 params
=> {"user"=>{"name"=>"テスト太郎" }}

このようにハッシュの中にハッシュが入っているのが確認できます。
ですのでストロングパラメーターを作成する際にはrequireメソッドを使う必要があります。

ターミナル
1
2
3
params.require(:user)
# 下記の内容が取得できる
{"name"=>"テスト太郎" }

form_forとform_tagではストロングパラメーターを定義するときの記述が異なりますので注意しましょう!

form_forでの各投稿フォームの作り方
リンクをコピーしました

form_forで各投稿フォームを作成するときは下記のように記述します。

erb
1
2
3
4
<%= form_for(@user) do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

このように「f.htmlタグ名 :カラム名」と指定します。
カラム名は保存される先のテーブルのカラム名を指定します。
つまり上の例だとusersテーブルのnameカラムに投稿した内容が送られることなります。
送信ボタンは「f.submit」とするだけで作成されます。

from_forは最初は記述が難しそうに感じますが、実は非常にシンプルに記述ができます。

form_forで使用できるhtmlタグ
リンクをコピーしました

form_forで使用できるhtmlタグ名には下記のような種類があります。

メソッド 用途
f.text_field 一行のテキスト投稿フォーム
f.text_area 複数行のテキスト投稿フォーム
f.number_field 数値入力ボックスを生成
f.email_field メールアドレス入力ボックスを生成
f.check_box データベースの情報を使わないでチェックボックスを生成
f.collection_check_boxes データベースの情報を元にチェックボックスを生成
f.select 選択肢を作成
f.collection_select データベースの情報を元に選択肢を生成
f.file_field ファイル選択ボックスを生成
f.datetime_field 日時の入力欄を生成
f.date_select 日付選択ボックスを生成
f.hidden_field 非表示のフォーム
f.submit 送信ボタンの生成

それでは個々の具体的な書き方を見てみましょう。

f.text_field
リンクをコピーしました

一行のテキスト投稿フォームを作成します。

text_filed
オプションとして下記の項目を設定できます。

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定
maxlength 入力可能な最大文字数の指定
erb
1
<%= f.text_field :name, class: "hoge", size: 30 %>

このように指定すると「hoge」というcssのhogeというクラスが指定され、幅が30文字になります。
ちなみに設定しないときの初期値は20になります。

f.text_area
リンクをコピーしました

複数行のテキスト投稿フォームを作成します。

text_area
オプションとして下記の項目を設定できます。

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定
maxlength 入力可能な最大文字数の指定
erb
1
<%= f.text_area :name, class: "hoge", size: "30x10" %>

このように指定すると「hoge」というcssのhogeというクラスが指定され、幅が30文字の行が10行表示されます。
ちなみに設定しないときの初期値は40x20になります。(※「x」はXの小文字)

f.number_field
リンクをコピーしました

数字を増減させるためのボタンが利用できるフォームを作成します。
直接フォームに数字を入力することもできますが、数値以外は入力できません。

number_field

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定
max 最大値の設定
min 最小値の設定
erb
1
<%= f.number_field :age, class: "hoge", min: 0, max: 1 %>

このように指定すると「hoge」というcssのクラスが指定され、最小値0、最大値が1の状態で投稿してもらうことができます。

f.email_field
リンクをコピーしました

メールアドレスを入力してもらうフォームを作成します。
投稿内容に「@」が含まれない時はメールアドレスをみなされずエラーとなります。

email_field

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定

f.check_box
リンクをコピーしました

チェックボックスを作成します。

check_box

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定
checked 初期状態をチェック状態にします
erb
1
<%= f.check_box :sex ,{}, "true", "false" %>

このように指定するとチェックされている時はtrueが、されていない時はfalseが送られます。

erb
1
<%= f.check_box :sex ,{checked: true}, "true", "false" %>

このように指定すると初期状態のチェックボックスがチェックされた状態になって表示されます。

f.collection_check_boxes
リンクをコピーしました

データベースの情報を元にチェックボックスを生成します。
テーブル同士の関係が多対多であるときに使用します。
書き方は下記の通りです。

erb
1
<%= f.collection_check_boxes(保存されるカラム名, オブジェクトの配列, カラムに保存される項目, チェックボックスに表示されるカラム名 ) %>

説明をみてもわかりづらいので実際の例をみてみましょう。
ユーザーは複数のグループに所属でき、グループはたくさんのユーザーを持つことができるとします。

erb
1
<%= f.collection_check_boxes :user_ids, User.all, :id, :name %>

このように記述すると下記のように複数の選択可能なチェックボックスを表示させることができます。

f.collection_check_boxes

コンパイルされると下記のコードになります。

html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<input type="hidden" name="group[user_ids][]" value="" />
<input type="checkbox" value="1" name="group[user_ids][]" id="group_job_ids_1" />
<label for="group_job_ids_1">programan</label>
<input type="checkbox" value="2" name="group[job_ids][]" id="group_job_ids_2" />
<label for="group_job_ids_2">programan_father</label>
<input type="checkbox" value="3" name="group[job_ids][]" id="group_job_ids_3" />
<label for="group_job_ids_3">programan_mother</label>
<input type="checkbox" value="4" name="group[job_ids][]" id="group_job_ids_4" />
<label for="group_job_ids_4">programan_bigsister</label>
<input type="checkbox" value="5" name="group[job_ids][]" id="group_job_ids_5" />
<label for="group_job_ids_5">programan_sister</label>
<input type="checkbox" value="6" name="group[job_ids][]" id="group_job_ids_6" />
<label for="group_job_ids_6">programan_bigbrother</label>
<input type="checkbox" value="7" name="group[job_ids][]" id="group_job_ids_7" />
<label for="group_job_ids_7">programan_brother</label>

「group[user_ids][]"」の「group」の部分は対応したモデル名を指していて自動で入ります。

実際下記のようにチェックをして投稿してみます。

投稿する

この時のparamsの構造をみてみましょう。

shell
1
2
params
=> "group"=>{"name"=>"ピカわか", "user_ids"=>["", "1", "5", "7"]}

※最初の「""」は「」の部分が入っています。

このようになっているためストロングパラメーターは下記のように記述します。
「{ user_ids: [] }」の部分がcollection_check_boxesの値を指しています。

コントローラー
1
2
3
def user_params
 params.require(:group).permit(:name, { user_ids: [] })
end

f.radio_button
リンクをコピーしました

ラジオボタンを作成します。
書き方は下記の通りです。

erb
1
<%= f.radio_button "保存されるカラム名", "カラムに保存される内容" %>

実際の例を見てみましょう。

erb
1
<%= f.radio_button :sex, "男" %><%= f.radio_button :sex, "女" %>

このように記述すると下記のように表示されます。

radio_button

男を選択しているとsexカラムに「男」という文字列が保存されます。
どれか一つしか選択させない場合に使います。
もちろん3つ以上でも記述が可能です。

オプションとして下記の項目が設定できます。

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定
checked trueと指定するとデフォルトでチェックが付いた状態になります

下のように記述すると「女」が初期状態で選択されます。

erb
1
性別:<%= f.radio_button :sex, 0 %><%= f.radio_button :sex, 1, checked: true %>

この場合は「女」を選択するとsexカラムに「1」という数字が保存されます。

f.select
リンクをコピーしました

データベースの情報を使わずにフォームで指定した選択肢を表示させます。
書き方は下記の通りです。

erb
1
<%= f.select :保存されるカラム名, [ ["表示される文字","保存される値"], ["表示される文字","保存される値"] ] %>

これだとわかりにくいので、実際の例を見てみましょう。

erb
1
<%= f.select :job_id, [ ["プログラマン講師",1], ["家電メーカー", 2], ["主婦", 3 ] ,["保育士", 4], ["学生", 5], ["営業", 6] ], prompt: "職業を選択してください" %>

例には「prompt: "表示するメッセージ"」を追加してみました。
promptは未選択の時に一番上に表示されるメッセージを定義できるオプションです。
上のコードは下記のように表示されます。

f.select

上の例だと「プログラマン講師」を選択すると「job_id」のカラムに「1」の値が保存されます。
実際にコンパイルされるコードは下のコードになります。

html
1
2
3
4
5
6
7
8
9
<select name="user[job_id]" id="user_job_id">
<option value="">職業を選択してください</option>
<option value="1">プログラマン講師</option>
<option value="2">家電メーカー</option>
<option value="3">主婦</option>
<option value="4">保育士</option>
<option value="5">学生</option>
<option value="6">営業</option>
</select>

プログラマン講師を選択した時のparamsで取得できるパラメーターは下記の通りです。

shell
1
2
params
=> "user"=><ActionController::Parameters {"job_id"=>"1"} permitted: false>

f.collection_select
リンクをコピーしました

データベースに保存されている情報を元に選択肢を表示させます。
書き方は下記の通りです。

erb
1
<%= f.collection_select(保存されるカラム名, オブジェクトの配列, カラムに保存される項目, 選択肢に表示されるカラム名 ) %>

説明をみてもわかりづらいので実際の例をみてみましょう。
今jobsテーブルのnameカラムに下記のレコードが保存されているとします。

collection_select
この6つのレコードのnameカラムを選択肢として投稿フォームに表示させ、選択した項目のidがusersテーブルのjob_idに保存したい時には下記のように定義します。

まずはusersコントローラーのnewアクションをこのように定義します。

コントローラー
1
2
3
def new
  @jobs = Job.all
end

これでjobsテーブルから全てのレコードを取得し、@jobsという変数に代入しました。

次にビューの方で下記のように記述します。

erb
1
<%= f.collection_select(:job_id, @jobs, :id, :name ) %>

するとこのように表示されます。

選択肢

@jobsの最初のレコードのnameカラムの値が順番に選択肢として表示されているのが確認できます。

ここで一番上の「プログラマン講師」を選択し、送信するとform_forの引数に渡したインスタンスのテーブルのjob_idというカラムにjobsテーブルのidカラムの数値が保存されます。

collection_selectではこのように引数に記述する順番が大事なので記述する際は気をつけましょう。

「f.select」と同じように「prompt: "表示するメッセージ"」を追記すると未選択時に表示するメッセージを定義することができます。

erb
1
<%= f.collection_select(:job_id, @jobs, :id, :name, {prompt: "表示するメッセージ"}) %>

選択肢

f.collection_selectにclassを与える場合は下記のように記述します。

erb
1
<%= f.collection_select(:job_id, @jobs, :id, :name, {prompt: "表示するメッセージ"}, {class: "hoge"}) %>

このようにしてあげるとclassを適用させることができます。
「prompt: ""」を書かないと適用されないので注意しましょう。

上のコードは下記のコードにコンパイルされます。

html
1
2
3
4
5
6
7
8
<select class="hoge" name="user[job_id]" id="user_job_id">
<option value="">表示するメッセージ</option>
<option value="1">プログラマン講師</option>
<option value="2">家電メーカー</option>
<option value="3">主婦</option>
<option value="4">保育士</option>
<option value="5">学生</option>
<option value="6">営業</option></select>

f.file_field
リンクをコピーしました

ファイルを送信する際のファイル選択ボックスを生成します。

file_field

f.file_fieldはlabelと組み合わせるとfont-awesomeのアイコンの画像と紐付けする事ができます。
labelについての詳しい使い方は後述します。

erb
1
2
<%= f.label :カラム名, for: “属性値”, class: fa fa-アイコン名” do %>
<%= f.file_field :カラム名, 属性: “属性値”, style: "display: none;" %>

例えば下記のように記述します。

erb
1
2
<%= f.label :image, for: file-input, class: fa fa-file-picture-o do %>
<%= f.file_field :image, id: file-input, style: "display: none;" %>

上のように記述すると下記のようになります。

アイコン画像

フォームを表示させたくない時に便利です。

f.datetime_field
リンクをコピーしました

日時の入力欄を作成します。

date_field

f.date_select
リンクをコピーしました

日付選択ボックスを生成します。

date_select

このタグには多数のオプションが用意されています。

オプションは下記のように指定します。

erb
1
<%= f.date_select :カラム名, {オプション名: } %>
オプション名 説明
discard_year 年を非表示
discard_month 月を非表示
discard_day 日付を非表示
use_month_numbers 月を数字で表示
start_year 開始年を指定(デフォルトは現在の5年前)
end_year 終了年を指定(デフォルトは現在の5年後)
default: { year: 年, month: 月, day: 日 } 最初に選択される日付を設定

基本は次のように指定します。

erb
1
2
#値をtrueにする
<%= f.date_select :カラム名, {discard: true} %>

開始年と終了年の指定は下記のように指定します。
片方だけでも指定できますし、両方指定することもできます。

erb
1
2
3
4
5
#開始年を1990年に指定
<%= f.date_select :カラム名, {start_year: 1990} %>

選択できる年を1990から2100に指定
<%= f.date_select :カラム名, {start_year: 1990, end_year: 2100} %>

最初に選択される日付を変更するには下記のように指定します。

erb
1
2
#最初の選択を2000年1月1日にする。
<%= f.date_select :カラム名, default: { year: 2000, month: 1, day: 1 } %>

f.hidden_field
リンクをコピーしました

非表示のフォームを作成します。
ユーザーのidなど、ユーザーがフォームから入力しない情報をパラメーターとして渡したいときに使用します。

erb
1
<%= f.hidden_field :カラム名, value: "値" %>

例えばユーザーidに現在ログインしているユーザーのidを入れたい場合は下記のように記述します。

erb
1
<%= f.hidden_field :user_id, value: current_user.id %>

配列に入れたい場合は下記のように記述します。

erb
1
<%= f.hidden_field 'モデル名[user_ids][]', value: current_user.id) %>

例えばグループに所属するユーザーであれば下記のような記述になります。

erb
1
<%= f.hidden_field 'group[user_ids][]', value: current_user.id) %>

上のコードはコンパイルされると下記のコードになります。

html
1
<input value="1" type="hidden" name="group[group[user_ids][]]" id="group_group[user_ids][]" />

同じようなタグとしてform_forのタグではないですが、hidden_field_tagがあります。
hidden_field_tagは単体でも使えますし、form_forの中でも使用することができます。
下記のように記述します。

erb
1
<%= hidden_field_tag :カラム名,  %>

上のf.hidden_fieldの例をhidden_field_tagで書くと下記のようになります。

erb
1
<%= hidden_field_tag :user_id, current_user.id %>

hidden_field_tagの方が若干簡単に書けますね。
hidden_field_tagで書いた場合、paramsで取得する時の書き方が異なるので注意しましょう。

erb
1
2
3
4
5
<%= form_for @user do |f| %>
  <%= f.text_field :name %>
  <%= hidden_field_tag :user_id, current_user.id %>
  <%= f.submit "送信" %>
<% end %>

上の場合、nameとuser_idを取り出すコードは下記のようになります。

ruby
1
2
3
4
5
# nameを取得する場合
params[:user][:name]

# user_idを取得する場合
params[:user_id]

f.submit
リンクをコピーしました

送信ボタンを作成します。

erb
1
<%= f.submit "ボタンの名前" %>

上のように記述すると下のような送信ボタンが生成されます。

erb
1
<%= f.submit "送信" %>

送信ボタン

実際に投稿フォームを作ってみよう
リンクをコピーしました

それでは実際にform_forを使って投稿フォームを作成してみましょう。
下記のコマンドを順に実行してみましょう。
①git clone -b form_for https://github.com/miyagit/programan_dojo.git

② cd programan_dojo

③ bundle install
→ rbenv: version ‘2.4.1’ is not installed と表示された場合は、ruby -v と実行してください。

ruby -vと実行し出てきたversion(例: 2.3.1)と出てきたら、

vim .ruby-versionとし、
ruby -vで出てきた値(例: 2.3.1)に書き換えてください。

続いてvim Gemfileとし、ruby 2.4.1と書いてある部分をruby -vで出てきた値(例: 2.3.1)に書き換えてください。

④ rails db:create && rails db:migrate && rails db:seed

環境構築が完了しました。と表示されると、
本当にrails applicationが動作するかrails sコマンドで起動しましょう。

rails sを起動し、ブラウザでlocalhost: 3000と入力して下記のような画面が出てくれば環境構築完了です!

環境構築

usersテーブルを確認しよう
リンクをコピーしました

今回はform_forでuserの新規登録画面を作成します。
その前にusersテーブルの構造を確認しておきましょう。
トップページを開くとusersテーブルにどんなカラムがあるのか確認できます。

今回のデータベース構造は下記のようになっています。

usersテーブル

内容 カラム名
名前 name
職業 job_id
性別 sex
年齢 age
身長 tall
体重 weight

jobsテーブル

内容 カラム名
名前 name

usersコントローラーのnewアクションを定義しよう
リンクをコピーしました

今回はform_forで新規登録画面を作成します。
それにはnewアクションを動かすのでまずはnewアクションを定義しましょう。
アクション内ではform_forの引数に渡すインスタンスを作成します。
また、職業の箇所はcollection_selectで選択肢を表示したいので、上の記事をよく読みcollection_selectに渡すインスタンスを生成してみましょう。

下記のようにusersコントローラーのnewアクションが定義されていれば大丈夫です。

コントローラー
1
2
3
4
def new
    @user = User.new
    @jobs = Job.all
end

投稿フォームを作成しよう
リンクをコピーしました

次にnew.html.erbにform_forを使って投稿フォームを作成しましょう。
使用するhtmlタグは下記の通りとします。

内容 カラム名
name text_field
job collection_select
sex number_field
age number_field
tall number_field
weight number_field

一番下には送信ボタンを作成する「f.submit」も書いておきましょう。
下記のように書かれていればうまく投稿フォームが作成されているはずです。

erb
1
2
3
4
5
6
7
8
9
10
11
<div class='content'>
    <%= form_for @user do |f| %>
    <%= f.text_field :name %>
    <%= f.collection_select :job_id, @jobs, :id, :name %>
    <%= f.number_field :sex %>
    <%= f.number_field :age %>
    <%= f.number_field :tall %>
    <%= f.number_field :weight %>
    <%= f.submit "送信" %>
    <% end %>
</div>

下記のアドレスを入力し、投稿画面を確認してみましょう。
http://localhost:3000/users/new

すると下記のような画面が確認できるはずです。

submit

form_forは表示される際、inputタグに変換されるため全て横並びになってしまいます。
これでは見にくいので
タグで改行をいれましょう。

erb
1
2
3
4
5
6
7
8
9
10
11
<div class='content'>
    <%= form_for @user do |f| %>
    <%= f.text_field :name %><br>
    <%= f.collection_select :job_id, @jobs, :id, :name %><br>
    <%= f.number_field :sex %><br>
    <%= f.number_field :age %><br>
    <%= f.number_field :tall %><br>
    <%= f.number_field :weight %><br>
    <%= f.submit "送信" %>
    <% end %>
</div>

するとこのようになりました。

input

ちゃんと縦に並び、みやすくなりましたね!

ここで1回ソースを確認し、form_forがrailsによってどのようにhtmlにコンパイルされたか確認してみましょう。
ダブルクリックをし、「ページのソースを表示」を選びましょう。
すると下記のコードに変換されているのが確認できます。

html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="✓" />
  <input type="hidden" name="authenticity_token" value="eShsYZ2AAknx2Ik2bIGVduAKQRIDwWtMpcuIgoQq3HwhAxLxhg02d3QAFTvTaW+OzaPajFLzsu4aH512aoTfQw==" />
  <input type="text" value="" name="user[name]" id="user_name" />
  <select name="user[job_id]" id="user_job_id">
  <option value="1">プログラマン講師</option>
  <option value="2">家電メーカー</option>
  <option value="3">主婦</option>
  <option value="4">保育士</option>
  <option value="5">学生</option>
  <option value="6">営業</option>
  </select>
  <input type="number" name="user[sex]" id="user_sex" />
  <input type="number" name="user[age]" id="user_age" />
  <input type="number" name="user[tall]" id="user_tall" />
  <input type="number" name="user[weight]" id="user_weight" />
  <input type="submit" name="commit" value="送信" data-disable-with="送信" />
</form>

このようformに変換されていますね。
ちゃんとcreateアクションが動くようにhttpメソッドも自動的にpostになっています。
inputタグの中のnameで指定している部分が入力されたデータが保存されるカラムになっています。

今回user[カラム名]としてあげることにより保存されるカラムを指定できます。
なぜname="カラム名"で指定できないのかはこのあと説明します。

さて、これでフォームはできましたが、このままだとどのフォームに何を入力していいかわかりませんね。
その時はlabelを使用します。

label
リンクをコピーしました

labelタグを作成します。
今回のnameカラムのフォームにラベルをつける時は下記のように記述します。

erb
1
2
<%= f.label :name %>
<%= f.text_field :name %>

label
このようにラベルがつきました。
今回はカラム名と同じになりましたが、自由に設定することもできます。
それには下記のように記述をします。

erb
1
2
<%= f.label :name, "名前:" %>
<%= f.text_field :name %>

label
こちらの方がわかりやすいですね!
同じように全てのフォームにラベルをつけてみましょう。

erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class='content'>
    <%= form_for @user do |f| %>
        <%= f.label :name, "名前:" %>
        <%= f.text_field :name %><br>
        <%= f.label :job_id, "職業:" %>
        <%= f.collection_select :job_id, @jobs, :id, :name %><br>
        <%= f.label :sex, "性別:" %>
        <%= f.number_field :sex %><br>
        <%= f.label :age, "年齢:" %>
        <%= f.number_field :age %><br>
        <%= f.label :tall, "身長:" %>
        <%= f.number_field :tall %><br>
        <%= f.label :weight, "体重:" %>
        <%= f.number_field :weight %><br>
        <%= f.submit "送信" %>
    <% end %>
</div>

これでだいぶわかりやすい投稿フォームになりました。

form
ソースを確認してみましょう。

html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="✓" />
  <input type="hidden" name="authenticity_token" value="nH1so7B0iPzSjGR7Gm8/lWH9q4bNDamGw1ej5560IYjEVhIzq/m8wldU+Halh8VtTFQwGJw/cCR8g7YTcBoitw==" />
        <label for="user_name">名前:</label>
        <input type="text" value="" name="user[name]" id="user_name" /><br>
        <label for="user_job_id">職業:</label>
        <select name="user[job_id]" id="user_job_id">
          <option value="1">プログラマン講師</option>
          <option value="2">家電メーカー</option>
          <option value="3">主婦</option>
          <option value="4">保育士</option>
          <option value="5">学生</option>
          <option value="6">営業</option></select><br>
        <label for="user_sex">性別:</label>
        <input type="number" name="user[sex]" id="user_sex" /><br>
        <label for="user_age">年齢:</label>
        <input type="number" name="user[age]" id="user_age" /><br>
        <label for="user_tall">身長:</label>
        <input type="number" name="user[tall]" id="user_tall" /><br>
        <label for="user_weight">体重:</label>
        <input type="number" name="user[weight]" id="user_weight" /><br>
        <input type="submit" name="commit" value="送信" data-disable-with="送信" />
</form>

このようにlabelタグにコンパイルされているのが確認できます。
labelタグはforで指定した文字とinputタグの中で指定したidを同じにするとフォーム部品と項目名を関連づけることができます。
f.labelとするだけでそれが上のように自動でコンパイルされます。

それでは実際に投稿した時にデータベースに保存されるよう、usersコントローラーにcreateアクションを定義してみましょう。
createメソッドを使用する時はストロングパラメーターを設定する必要があります。
下記のようにcreateアクション、およびストロングパラメーターの記述をしましょう。

コントローラー
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class UsersController < ApplicationController
    def new
        @user = User.new
        @jobs = Job.all
    end

    def create
        User.create(user_params)
        redirect_to root_path
    end

    private
    def user_params
        params.require(:user).permit(:name, :job_id, :sex, :age, :tall, :weight)
    end
end

どうしてこのように記述するかはこのあと説明します。

form_forでの保存方法の注意点
リンクをコピーしました

form_tagで投稿フォームを作成した時に指定するストロングパラメーターは上の例だと下記のような記述でした。

コントローラー
1
params.permit(:name, :job_id, :sex, :age, :tall, :weight)

しかし上の例をみてもわかる通りform_forを使った時は下記のように記述します。

コントローラー
1
params.require(:user).permit(:name, :job_id, :sex, :age, :tall, :weight)

form_tagだと「params.permit(:キー名)」でしたが、form_forだと「params.require(:モデル名).permit(:カラム名)」になります。
これはなぜでしょう?

これは2つのparamsの構造が違うためです。
binding.pryを使い、paramsの中身を確認してみましょう。
Gemfileの一番下に下記のコードを追記してください。

Gemfile
1
gem 'pry-rails'

その後、ターミナルで「bundle install」コマンドを実行してください。

users_controllerのcreateアクションを下記のように編集してください。

コントローラー
1
2
3
4
5
def create
  User.create(user_params)
    binding.pry
    redirect_to root_path
end

次に下記のアドレスから投稿画面にいき、テスト投稿をしてみましょう。

http://localhost:3000/users/new

すると送信後、トップページへ遷移せずに現在の画面にとどまり続けるはずです。
この状態でサーバーを起動したターミナルを確認してみましょう。

params
このようにコマンド入力待ちの状態になっているので、「pramas」と入力してください。
するとparamsの中身が表示されるので、確認をしてみましょう。

ターミナル
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[1] pry(#<UsersController>)> params
=> <ActionController::Parameters 
{
  "utf8"=>"✓",  "authenticity_token"=>"P9L/zj5tIU3+L3cUv7kvFRbX34RET0rwbMymMf8/9P6shtNnJ8UejzDmax2t59nG6gdhnYBzA7n3JspBE/UuvQ==",
  "user"=><ActionController::Parameters 
  {
    "name"=>"テスト太郎",
    "job_id"=>"1",
    "sex"=>"0",
    "age"=>"60",
    "tall"=>"155",
    "weight"=>"50"
  }permitted: false>,
  "commit"=>"送信",
  "controller"=>"users",
  "action"=>"create"
    } permitted: false>

上のような結果が返ってきました。
(※確認後はexitコマンドでコンソールモードから抜けましょう。)
もし今回の投稿フォームをform_tagを使用して作成した時のparamsは下記のようになります。

ターミナル
1
2
3
4
5
6
7
8
9
10
11
12
13
[1] pry(#<UsersController>)> params
=> <ActionController::Parameters {
  "utf8"=>"✓", "authenticity_token"=>"SAf1Hfm/9XLsmT+PlH7auww2dNicdQ9lmx9qkjWzBJ7bU9m04BfKsCJQI4aGICxo8ObKwVhJRiwA9Qbi2Xne3Q==",
  "name"=>"テスト二郎",
  "job_id"=>"1",
  "sex"=>"0",
  "age"=>"50",
  "tall"=>"155",
  "weight"=>"50",
  "commit"=>"送信",
  "controller"=>"users",
  "action"=>"create"
} permitted: false>

この2つの違いはparamsの構造です。
form_forの方はハッシュの中にハッシュが入っているのが確認できると思います。
userというキーのバリューがハッシュになっているためです。
なのでparamsからキーがnameのバリューを取り出す場合には「params[:user][:name]」のように記述する必要があります。

コンパイルされたinputタグの中で「name="user[カラム名]"」となっていたのはこのためです。
ですのでcreateアクションでフォームに投稿された内容をデータベースに保存する記述は下記のようになります。データベースに保存する記述は下記のようになります。

コントローラー
1
2
3
def create
  User.create(name: params[:user][:name], job_id: params[:user][:job_id], sex: params[:user][:sex], age: params[:user][:age], tall: params[:user][:tall], weight[:user][:tall])
end

この記述だと非常に長くなってしまいますね。
そこで登場するのがrequireメソッドです。
requireメソッドをparamsに対して使うとparamsの中から引数に指定したハッシュが取り出せます。

もう一度binding.pryを使ってrequireメソッドを確認してみましょう。

下記のアドレスから投稿画面にいき、テスト投稿をしてみましょう。

http://localhost:3000/users/new

その後、「params.require(:user)」と入力してください。
すると下記のハッシュが返ってくるのが確認できます。

ターミナル
1
2
3
4
5
6
7
8
9
[1] pry(#<UsersController>)> params.require(:user)
=> <ActionController::Parameters {
  "name"=>"テスト太郎",
    "job_id"=>"1",
    "sex"=>"0",
    "age"=>"50",
    "tall"=>"160",
    "weight"=>"55"
    } permitted: false>

このようにparamsの中から引数に指定したuserの値が取り出せたことが確認できますね!
そのあとに続けるpermitメソッドはこのハッシュの中からデータベースに保存したいキーを指定することができます。
このメソッドによって悪意のあるリクエストが送られてきてもpermitメソッドで指定したキーしか保存されないのでセキュリティが高まります。
この2つのメソッドを利用することでcreateアクションは下記のようにかなり簡潔にかけますね!

コントローラー
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# requireメソッドを使わない時
def create
  User.create(name: params[:user][:name], job_id: params[:user][:job_id], sex: params[:user][:sex], age: params[:user][:age], tall: params[:user][:tall], weight[:user][:tall])
end

# ストロングパラメーターでrequireメソッドとpermitメソッドを使用した時
def create
    User.create(user_params)
end

private
def user_params
    params.require(:user).permit(:name, :job_id, :sex, :age, :tall, :weight)
end

自分で投稿フォームを編集してみよう
リンクをコピーしました

今作成した投稿フォームのhtmlタグを他のものに変えた時にどういう表示になるのか、また性別は0か1なので0から1までしか入力できないようにオプション指定をしてみたりと自分で色々と編集を加えてみましょう。

まとめ

form_forは今回のように投稿フォームが保存されるテーブルがある時に使い、検索フォームなどフォームから送信されたデータが保存されるテーブルがない場合はform_tagを使用すると覚えておきましょう!