更新日:
【Rails】 form_forの使い方をマスターしよう!
form_forとは、railsで情報を送信するためのヘルパーメソッドです。form_forを使うことにより、簡単に入力フォームに必要なHTMLを作成することができます。
1
2
3
<%= form_for('モデルクラスのインスタンス') do |f| %>
<%# フォーム内容 %>
<% end %>
form_forの引数には、モデルクラスのインスタンスを指定します。form_foは、主にテーブルにレコードを新規作成、更新するときに利用します。
form_forの基礎知識
この章では、form_forについて基本的な使い方など解説します。
form系ヘルパーメソッドの使い分け
railsで投稿フォームを作成するにはセキュリティの面から直接inputタグを利用して書くことはありません。
投稿フォームを作成するにはform_tagやform_for
、form_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 %>
上のコードはコンパイルされると下記のコードになります。
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メソッドを指定しなくても自動で振り分けてくれるというわけです。
非常に便利ですね!
ネストをしている時の書き方
ルーティングでネストを定義している時は記述が変わります。
記事に関するコメントを投稿するフォームを例に挙げてみます。
ルーティングは下記のようにしています。
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 %>
コンパイルされると下記のようなコードになります。
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="✓" />
# 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="✓" /><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の基礎から実践的なノウハウまで学べる!
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
一行のテキスト投稿フォームを作成します。
オプションとして下記の項目を設定できます。
メソッド | 用途 |
---|---|
class | cssのクラスの指定 |
size | フォームの幅を指定 |
maxlength | 入力可能な最大文字数の指定 |
1
<%= f.text_field :name, class: "hoge", size: 30 %>
このように指定するとhoge
というcssのhogeというクラスが指定され、幅が30文字になります。
ちなみに設定しないときの初期値は20になります。
f.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
数字を増減させるためのボタンが利用できるフォームを作成します。
直接フォームに数字を入力することもできますが、数値以外は入力できません。
メソッド | 用途 |
---|---|
class | cssのクラスの指定 |
size | フォームの幅を指定 |
max | 最大値の設定 |
min | 最小値の設定 |
1
<%= f.number_field :age, class: "hoge", min: 0, max: 1 %>
このように指定するとhoge
というcssのクラスが指定され、最小値0、最大値が1の状態で投稿してもらうことができます。
f.search_field
検索フォームを作成します。
text_fieldと同じに見えますが、検索フォームはinputタグにtype="search"
が記述されているフォームです。
この記述があることによりフォームの右に「x」ボタンが表示されるようになります。
「x」ボタンをクリックすると入力された内容をリセットすることができます。
ransackのようなgemを使って検索フォームを作るときなどに使います。
f.email_field
メールアドレスを入力してもらうフォームを作成します。
投稿内容に@
が含まれない時はメールアドレスをみなされずエラーとなります。
メソッド | 用途 |
---|---|
class | cssのクラスの指定 |
size | フォームの幅を指定 |
f.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 %>
このように記述すると下記のように複数の選択可能なチェックボックスを表示させることができます。
コンパイルされると下記のコードになります。
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, "女" %>女
このように記述すると下記のように表示されます。
男を選択していると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
を定義します。
またtrue
、false
の部分に文字列を入れるとその文字が表示されます。
これだとわかりにくいので、実際の例を見てみましょう。
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
は未選択の時に一番上に表示されるメッセージを定義できるオプションです。
上のコードは下記のように表示されます。
上の例だと「プログラマン講師」を選択するとjob_id
のカラムに「1」の値が保存されます。
実際にコンパイルされるコードは下のコードになります。
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カラムに下記のレコードが保存されているとします。
この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を適用させることができます。
第五引数のオプションの定義部分も空として記述する必要があります。
上のコードは下記のコードにコンパイルされます。
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
ファイルを送信する際のファイル選択ボックスを生成します。
下記のように記述します。
1
<%= f.file_filed :保存されるカラム名 %>
f.file_field
はlabel
と組み合わせると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
日時の入力欄を作成します。
f.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) %>
上のコードはコンパイルされると下記のコードになります。
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 "送信" %>
投稿フォームを作成してみよう
この章では、実際に手を動かしながら投稿フォームの作成を行います。
環境を構築する
環境構築の準備をします。
下記のコマンドを順番に実行してみましょう。
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)に書き換えてください。
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のアドレスを入力し、投稿画面を確認してみましょう。
すると下記のような画面が確認できるはずです。
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>
するとこのようになりました。
ちゃんと縦に並び、みやすくなりましたね!
ここで1回ソースを確認し、form_forがrailsによってどのように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 %>
このようにラベルがつきました。
今回はカラム名と同じになりましたが、自由に設定することもできます。
それには下記のように記述をします。
1
2
<%= f.label :name, "名前:" %>
<%= f.text_field :name %>
こちらの方がわかりやすいですね!
同じように全てのフォームにラベルをつけてみましょう。
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>
これでだいぶわかりやすい投稿フォームになりました。
ソースを確認してみましょう。
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の一番下に下記のコードを追記してください。
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のアドレスから投稿画面にいき、テスト投稿をしてみましょう。
すると送信後、トップページへ遷移せずに現在の画面にとどまり続けるはずです。
この状態でサーバーを起動したターミナルを確認してみましょう。
このようにコマンド入力待ちの状態になっているので、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を作成することが出来る
- 作成した投稿フォームがモデルに基づいている場合に使う