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

Rails

form_withとは

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

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

form_withはrails5.1から追加されたフォームを作成するためのヘルパーメソッドです。
それ以前はfor_tag、form_forと言ったヘルパーメソッドが使われていました。

form_tagはフォームに入力されたデータを保存する必要がない時に使われます。

ビューファイル | form_tagの書き方
1
2
3
4
<%= form_tag('/main', method: :post) do %> 
  <input type="text" name="nickname"> 
  <input type="submit"> 
<% end %>

それに対し入力されたデータを保存する必要があるときはform_forを使用します。

ビューファイル | form_forの書き方
1
2
3
4
<%= form_for(@user) do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

上の例文を見るとわかるようにform_forだとFormBuilderオブジェクトのヘルパーメソッドを使用している事がわかります。
form_tagとform_forで書き方が異なるのは不便なので、form_withではどちらの場合もFormBuilderオブジェクトのヘルパーメソッドを使って記述する事ができるようになりました。

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

それでは実際の使い方を確認してみましょう。
まずはform_tagのように入力された情報をデータベースに保存しない時の記述です。

ビューファイル | form_withの書き方
1
2
3
<%= form_with url: "パス" do |form| %>
  フォーム内容
<% end %>

下記のように記述します。

ビューファイル | form_withの書き方
1
2
3
<%= form_with url: root_path do |form| %>
  フォーム内容
<% end %>

次はデータベースに保存する時の記述です。

ビューファイル | form_withの書き方
1
2
3
<%= form_with model: モデルクラスのインスタンス do |form| %>
  フォーム内容
<% end %>

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

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

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

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

コントローラーで作成したインスタンスがnewメソッドで新たに作成されて何も情報を持っていなければ自動的にcreateアクションへ、findメソッドなどで作成され、すでに情報を持っている場合はupdateアクションへ自動的に振り分けてくれます。

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

ビューファイルを下記のように記述するとします。

ビューファイル
1
2
3
4
<%= form_with model: @user do |form| %>
  <%= form.text_field :name %>
  <%= form.submit %>
<% end %>

コンパイルされると下記のようにcreateアクションが動くパスに変換されます。

html | createアクションが動くようにコンパイル
1
<form action="/users" method="post" data-remote="true">

editアクションの時は下記のようになります。

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

コンパイルされると下記のように各アクションが動くパスに変換されます。

html | updateアクションが動くようにコンパイル
1
2
<form action="/users/"編集するレコードのid" method="post" data-remote="true">
<input type="hidden" name="_method" value="patch">

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

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

コントローラー | ネストの場合
1
2
3
4
5
6
7
8
9
def new
  @article = Article.find(params[:article_id])
  @comment = Comment.new
end

def edit
  @article = Article.find(params[:article_id])
  @comment = Comment.find(params[:id])
end

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

ビューファイル | ネストの場合
1
2
3
4
<%= form_with model: [@article, @comment] do |form| %>
  <%= form.text_field :text %>
  <%= form.submit %>
<% end %>

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

html | create・updateアクションが動くようにコンパイル
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属性を付けることができます。

ビューファイル | html属性の付け方
1
<%= form_with @user, 属性: ‘属性値' do |form| %>

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

ビューファイル
1
<%= form_with @user, id: 'new_form' do |form| %>

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

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

ビューファイル | アクション名で記述
1
2
3
4
<%= form_with @user, url: {controller: 'users', action: 'index' } do  |form| %>
  <%= form.text_field :name %>
  <%= form.submit %>
<% end %>

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

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

ビューファイル | 投稿フォームの作成
1
2
3
4
<%= form_with model: @user do |form| %>
  <%= form.text_field :name %>
  <%= form.submit %>
<% end %>

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

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

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

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

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

それではそれぞれのタグの具体的な使い方を見ていきます。

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

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

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

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

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

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

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

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

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

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

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

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

number_field

メソッド 用途
class cssのクラスの指定
size フォームの幅を指定
max 最大値の設定
min 最小値の設定
ビューファイル | number_field
1
<%= form.number_field :age, class: "hoge", min: 1, max: 150 %>

このように指定すると「hoge」というcssのクラスが指定され、最小値1、最大値が150の範囲でしか投稿できないようになります。

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

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

email_field

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

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

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

check_box

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

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

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

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

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

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

ビューファイル | collection_check_boxes
1
<%= form.collection_check_boxes(保存されるカラム名, オブジェクトの配列, カラムに保存される項目, チェックボックスに表示されるカラム名 ) %>

説明を見るよりも実際の例を見た方がわかりやすいので例をあげて確認してみます。
ユーザーは複数のグループに所属でき、グループはたくさんのユーザーを持つことができるとします。

ビューファイル
1
<%= form.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_user_ids_1" />
<label for="group_user_ids_1">programan</label>
<input type="checkbox" value="2" name="group[user_ids][]" id="group_user_ids_2" />
<label for="group_user_ids_2">programan_father</label>
<input type="checkbox" value="3" name="group[user_ids][]" id="group_user_ids_3" />
<label for="group_user_ids_3">programan_mother</label>
<input type="checkbox" value="4" name="group[user_ids][]" id="group_user_ids_4" />
<label for="group_user_ids_4">programan_bigsister</label>
<input type="checkbox" value="5" name="group[user_ids][]" id="group_user_ids_5" />
<label for="group_user_ids_5">programan_sister</label>
<input type="checkbox" value="6" name="group[user_ids][]" id="group_user_ids_6" />
<label for="group_user_ids_6">programan_bigbrother</label>
<input type="checkbox" value="7" name="group[user_ids][]" id="group_user_ids_7" />
<label for="group_user_ids_7">programan_brother</label>

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

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

投稿する

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

ターミナル
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

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

ラジオボタンを作成します。
下記の通りに記述します。

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

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

ビューファイル | radio_buttonの例
1
<%= form.radio_button :gender, "男" %><%= form.radio_button :gender, "女" %>

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

radio_button

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

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

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

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

ビューファイル | radio_buttonの例
1
性別:<%= form.radio_button :gender, 0 %><%= form.radio_button :gender, 1, checked: true %>

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

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

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

ビューファイル | select
1
<%= form.select :保存されるカラム名, [ ["表示される文字","保存される値"], ["表示される文字","保存される値"] ] %>

上の説明だとわかりにくいので、実際の例を見て確認してみましょう。

ビューファイル | selectの例
1
<%= form.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で取得できるパラメーターは下記の通りです。

ターミナル
1
2
params
=> "user"=><ActionController::Parameters {"job_id"=>"1"} permitted: false>

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

データベースに保存されている情報を元に選択肢を表示させます。
下記のように記述します。

ビューファイル | collection_select
1
<%= form.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という変数に代入しました。

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

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

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

選択肢

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

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

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

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

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

選択肢

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

ビューファイル | classの付け方
1
<%= form.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>

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

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

file_field

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

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

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

ビューファイル | 書き方の例
1
2
<%= form.label :image, for: file-input, class: fa fa-file-picture-o do %>
<%= form.file_field :image, id: file-input, style: "display: none;" %>

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

アイコン画像

フォームを表示させずにアイコンをクリックすればよくなるのでビューをスッキリさせることができます。

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

日時の入力フォームを作成します。

date_field

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

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

date_select

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ビューファイル | 使い方の例
1
<%= form.hidden_field :user_id, value: current_user.id %>

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

ビューファイル | 配列に入れる場合
1
<%= form.hidden_field 'モデル名[user_ids][]', value: current_user.id) %>

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

ビューファイル | 記述例
1
<%= form.hidden_field 'group[user_ids][]', value: current_user.id) %>

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

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

上のform.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_with model: @user do |form| %>
  <%= form.text_field :name %>
  <%= hidden_field_tag :user_id, current_user.id %>
  <%= form.submit "送信" %>
<% end %>

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

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

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

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

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

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

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

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

送信ボタン

labelを貼ってみよう
リンクをコピーしました

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

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

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

ビューファイル | 書き方の例
1
2
<%= form.label :name, "名前:" %>
<%= form.text_field :name %>

label
こちらの方がわかりやすいですね!

ajax処理について
リンクをコピーしました

form_withでフォームを作成するとデフォルトでajax処理が行われるようになります。
これを無効にしたい場合は下記のように記述します。

ビューファイル | ajax処理を無効
1
<%= form_with model: @user, local: true do |form| %>
まとめ

・form_withはrails5.1から用意されたフォームを作るためのヘルパーメソッドです。
・使用すると簡単に安全な入力フォームを作成することができます。
・使用できるhtmlタグもたくさん用意されているので大変便利です。