すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Rails

更新日:

【Rails】 form_forの使い方をマスターしよう!

ぴっかちゃん
ぴっかちゃん

form_forとは、railsで情報を送信するためのヘルパーメソッドです。form_forを使うことにより、簡単に入力フォームに必要なHTMLを作成することができます。

ビューファイル | form_forの基本構文
1
2
3
<%= form_for('モデルクラスのインスタンス') do |f| %>
  <%# フォーム内容 %>
<% end %>

form_forの引数には、モデルクラスのインスタンスを指定します。form_foは、主にテーブルにレコードを新規作成、更新するときに利用します。

form_forの基礎知識

この章では、form_forについて基本的な使い方など解説します。

form系ヘルパーメソッドの使い分け

railsで投稿フォームを作成するにはセキュリティの面から直接inputタグを利用して書くことはありません。

投稿フォームを作成するにはform_tagform_forform_withといったヘルパーメソッドを使用します。

投稿フォームに投稿された内容を保存するテーブルが存在するときにはform_forを使います。

それに対し検索フォームのようなフォームは検索ワードを入力してもらうだけで、そのワードはデータベースに保存する必要はないですよね?

そのような場合のフォームは、form_tagで作成します。

form_forの使い方

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

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

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

ビューファイル
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])でコメントする記事を取得しています。
ビュー側は下記のように引数に配列を渡す形になります。

ビューファイル
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属性を付けることができます。

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

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

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

アクション名で記述してみよう

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

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でf.メソッドの形でフォームを作成した場合は下記のようになります。

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

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

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

form_forとform_tagではストロングパラメーターを定義するときの記述が異なりますので注意しましょう!
※form_forでもform_tagと同じようにinputタグなどで記述した場合はform_tagと同じ構造になります。

form_forでの各投稿フォームの作り方

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

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

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

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

開発現場の知識も学びたい方におすすめの1冊

こちらの「現場で使える Ruby on Rails 5速習実践ガイド」の技術書がおすすめです。

Ruby on Railsを扱うための最低限必要なRubyの基礎からRailsアプリケーションの開発方法、現場で必要な知識まで体系的に学ぶことができます。

実際の現場に必要な知識はもちろんですが、これまで学習した内容をしっかりと知識として定着することができる1冊です!

現場で使える Ruby on Rails 5速習実践ガイド
現場で使える Ruby on Rails 5速習実践ガイド

Ruby on Railsの基礎から実践的なノウハウまで学べる!

form_forで使用できるhtmlタグ

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

メソッド 用途
f.text_field 一行のテキスト投稿フォーム
f.text_area 複数行のテキスト投稿フォーム
f.number_field 数値入力ボックスを生成
f.search_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 入力可能な最大文字数の指定
ビューファイル
1
<%= f.text_field :name, class: "hoge", size: 30 %>

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

f.text_area

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

text_area

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

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定
maxlength 入力可能な最大文字数の指定
ビューファイル
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 最小値の設定
ビューファイル
1
<%= f.number_field :age, class: "hoge", min: 0, max: 1 %>

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

f.search_field

検索フォームを作成します。

search_field

text_fieldと同じに見えますが、検索フォームはinputタグにtype="search"が記述されているフォームです。
この記述があることによりフォームの右に「x」ボタンが表示されるようになります。
「x」ボタンをクリックすると入力された内容をリセットすることができます。

searc_field

ransackのようなgemを使って検索フォームを作るときなどに使います。

f.email_field

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

email_field

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

f.check_box

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

check_box

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定
checked 初期状態をチェック状態にします
ビューファイル | 書き方の例
1
<%= f.check_box :保存するカラム名 ,{オプション}, "チェック時の値", "未チェック時の値" %>

具体的には下記のように使います。

ビューファイル
1
Check box: <%= f.check_box :sex ,{}, "true", "false" %>

このように指定すると上の画像のチェックボックスが作成されます。
チェックされている時はtrueが、されていない時はfalseがsexカラムに保存されます。

classを指定したい場合は{}の中に記述します。

ビューファイル
1
Check box: <%= f.check_box :sex ,{ class: "hoge" }, "true", "false" %>

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

ビューファイル
1
<%= f.check_box :sex, { checked: true }, "true", "false" %>

複数選択したときにそれぞれの値を配列として渡すこともできます。
その際はオプションで下記のように記述します。

ビューファイル
1
<%= f.check_box :配列名, { multiple: true }, "チェック時の値", nil %>

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

ビューファイル | 書き方の例
1
2
3
4
<p>ユーザー1: <%= f.check_box :user_ids ,{ multiple: true }, 1, nil %></p>
<p>ユーザー2: <%= f.check_box :user_ids ,{ multiple: true }, 2, nil %></p>
<p>ユーザー3: <%= f.check_box :user_ids ,{ multiple: true }, 3, nil %></p>
<p>ユーザー4: <%= f.check_box :user_ids ,{ multiple: true }, 4, nil %></p>

すると下のようなチェックボックスができます。

チェックボックス

またこの時未チェック時のnilを下記のように省略して書くこともできます。

ビューファイル | 書き方の例
1
2
3
4
<p>ユーザー1: <%= f.check_box :user_ids ,{ multiple: true }, 1 %></p>
<p>ユーザー2: <%= f.check_box :user_ids ,{ multiple: true }, 2 %></p>
<p>ユーザー3: <%= f.check_box :user_ids ,{ multiple: true }, 3 %></p>
<p>ユーザー4: <%= f.check_box :user_ids ,{ multiple: true }, 4 %></p>

ですがこのままだとチェックをしなかった時の値も渡ってしまいます。
上の例のチェックボックスを全てチェックしたときに渡される値を確認してみます。

渡される値の確認 -->
1
"user"=>{"user_ids"=>["0", "1", "0", "2", "0", "3", "0", "4"]}

このようにチェックしなかった時の0も自動で入ってしまいます。
これでは困りますね。
これを防ぐにはオプションにinclude_hidden: falseを追記します。

ビューファイル
1
<%= f.check_box :配列名, { multiple: true, include_hidden: false }, "チェック時の値" %>

先ほどのコードに追記してみます。

ビューファイル | 書き方の例
1
2
3
4
<p>ユーザー1: <%= f.check_box :user_ids ,{ multiple: true, include_hidden: false }, 1 %></p>
<p>ユーザー2: <%= f.check_box :user_ids ,{ multiple: true, include_hidden: false }, 2 %></p>
<p>ユーザー3: <%= f.check_box :user_ids ,{ multiple: true, include_hidden: false }, 3 %></p>
<p>ユーザー4: <%= f.check_box :user_ids ,{ multiple: true, include_hidden: false }, 4 %></p>

この時に渡される値を確認してみます。

渡される値の確認 -->
1
"user"=>{"user_ids"=>["1", "2", "3", "4"]}

今度はしっかりとチェックした時の値だけ渡るようになりました。

f.collection_check_boxes

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

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

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

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

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

f.collection_check_boxes

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

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の構造をみてみましょう。

コンソール
1
2
params
=> "group"=>{"name"=>"ピカわか", "user_ids"=>["", "1", "5", "7"]}

※最初の「""」は<input type="hidden" name="group[user_ids][]" value="" />の部分が入っています。

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

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

f.radio_button

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

ビューファイル
1
<%= f.radio_button "保存されるカラム名", "カラムに保存される内容" %>

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

ビューファイル
1
<%= f.radio_button :sex, "男" %><%= f.radio_button :sex, "女" %>

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

radio_button

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

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

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

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

ビューファイル
1
性別:<%= f.radio_button :sex, 0 %><%= f.radio_button :sex, 1, checked: true %>

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

f.select

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

ビューファイル
1
<%= f.select :保存されるカラム名, [ ["表示される文字","保存される値"], ["表示される文字","保存される値"], {オプション}, {htmlオプション} ] %>

第三引数のオプションを定義する部分と第四引数のhtmlオプションは省略できます。
ただし、第三引数のオプションを定義しないで第四引数のhtmlオプションを定義するときは第三引数は省略できないので空の{ }として記述します。

第三引数にはpromptオプションinclude_blankオプションを指定できます。
promptオプションは未選択の時に一番上に表示されるメッセージを定義できるオプションです。

include_blankオプションは先頭に表示されるメッセージに空白行を表示するオプションです。

include_blank: trueのような形で使用します。使用しないときはfalseを定義します。
またtruefalseの部分に文字列を入れるとその文字が表示されます。

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

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

第三引数と第四引数の中身は1つなら上の例のように{ }は省略できます。
複数の場合は下記のようになります。

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

例には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で取得できるパラメーターは下記の通りです。

コンソール
1
2
params
=> "user"=><ActionController::Parameters {"job_id"=>"1"} permitted: false>

f.collection_select

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

ビューファイル
1
<%= f.collection_select(保存されるカラム名, オブジェクトの配列, カラムに保存される項目, 選択肢に表示されるカラム名, {オプション}, {htmlオプション} ) %>

第五引数のオプションを定義する部分と第六引数のhtmlオプションはf.selectと同様に扱います。

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

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

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

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

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

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

ビューファイル
1
<%= f.collection_select(:job_id, @jobs, :id, :name ) %>

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

選択肢

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

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

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

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

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

選択肢

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

ビューファイル
1
<%= f.collection_select(:job_id, @jobs, :id, :name, { }, {class: "hoge"}) %>

このようにしてあげるとclassを適用させることができます。
第五引数のオプションの定義部分も空として記述する必要があります。

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

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
1
<%= f.file_filed :保存されるカラム名 %>

file_field

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

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

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

ビューファイル
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

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

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

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

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

ビューファイル
1
2
#値をtrueにする
<%= f.date_select :カラム名, {discard: true} %>

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

ビューファイル
1
2
3
4
5
#開始年を1990年に指定
<%= f.date_select :カラム名, {start_year: 1990} %>

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

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

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

f.hidden_field

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

ビューファイル
1
<%= f.hidden_field :カラム名, value: "値" %>

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

ビューファイル
1
<%= f.hidden_field :user_id, value: current_user.id %>

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

ビューファイル
1
<%= f.hidden_field 'モデル名[user_ids][]', value: current_user.id) %>

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

ビューファイル
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の中でも使用することができます。
下記のように記述します。

ビューファイル
1
<%= hidden_field_tag :カラム名,  %>

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

ビューファイル
1
<%= hidden_field_tag :user_id, current_user.id %>

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

ビューファイル
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を取り出すコードは下記のようになります。

コントローラーなど
1
2
3
4
5
# nameを取得する場合
params[:user][:name]

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

f.submit

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

ビューファイル
1
<%= f.submit "ボタンの名前" %>

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

ビューファイル
1
<%= f.submit "送信" %>

送信ボタン

投稿フォームを作成してみよう

この章では、実際に手を動かしながら投稿フォームの作成を行います。

環境を構築する

環境構築の準備をします。
下記のコマンドを順番に実行してみましょう。

  1. git clone -b form_for https://github.com/miyagit/programan_dojo.git
  2. cd programan_dojo
  3. 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)に書き換えてください。

4.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」も書いておきましょう。
下記のように書かれていればうまく投稿フォームが作成されているはずです。

ビューファイル
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タグに変換されるため全て横並びになってしまいます。
これでは見にくいので
タグで改行をいれましょう。

ビューファイル
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カラムのフォームにラベルをつける時は下記のように記述します。

ビューファイル
1
2
<%= f.label :name %>
<%= f.text_field :name %>

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

ビューファイル
1
2
<%= f.label :name, "名前:" %>
<%= f.text_field :name %>

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

ビューファイル
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アクションを下記のように編集してください。

users_controller.rb -->
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は、railsで情報を送信するためのヘルパーメソッド
  • form_forを使うことにより、簡単に入力フォームに必要なHTMLを作成することが出来る
  • 作成した投稿フォームがモデルに基づいている場合に使う