【Rails入門説明書】form_withについて解説
はじめに
Rails5.1で導入されたform_withヘルパーは、非推奨(将来的になくなる)になったform_forヘルパーとform_tagヘルパーの代わりとなるヘルパーです。
つまり、form_withヘルパーは、form_forヘルパーと同等の動きをするヘルパーと言えます。
ただし、当然ながら改善点もありますし、form_tagヘルパーとも統合されていますので、機能的には拡張されていると言えます。
そもそも、form_forヘルパーはよく使うヘルパーの1つでしたので、form_withヘルパーも同様によく使うことになります。
今回は、form_withヘルパーについては、form_forヘルパーと比較することで詳しく解説しますので、是非お役立てください。
なお、form_forヘルパーについては、「【Rails入門説明書】form_forについて解説」で詳しく解説しています。まだお読みでない場合は、先にお読みいただくことをおすすめします。
冒頭で記載しているように、form_withヘルパーは、Railsのバージョンが5.1以降でなければ使用できません。コマンドプロンプトで以下のコマンドを実行し、表示されるRailsのバージョンが5.1未満の場合は、5.1以上のバージョンをインストールしてください。
[bash]
rails -v
[/bash]
form_withヘルパーを読み解く
form_withヘルパーは、Viewファイルで使用することで、簡単にフォームを生成することができるヘルパーです。同時に、入力値の送信先もシンプルに設定でき、コントローラへのデータ引き継ぎもスムーズに行うことができます。
そんなform_withについて、まずはその動きを追って確認してみましょう。
環境設定
プログラムコードやHTMLを確認しますので、まずはテスト環境を設定します。
コマンドプロンプトを起動して、以下のコマンドを実行してください。
※詳細は、「【Rails入門説明書】scaffoldについて解説」を確認してください。
$rails new formw_test
$cd formw_test
$rails generate scaffold User name:string age:integer email:string password:string note:text
$rails generate scaffold Item title:string price:integer user_id:integer
$rake db:migrate
$rails c
$User.create(name:”Arioka”, age:30, email:”dai@hese.jp”, password:”0000″, note:”member”)
$User.create(name:”Yamada”, age:28, email:”ryo@hese.jp”, password:”1111″, note:”top”)
$Item.create(title:”ring”, price:50000, user_id:2)
$Item.create(title:”necklace”, price:20000, user_id:2)
$Item.create(title:”computer”, price:200000, user_id:1)
$exit
[/bash]
モデルファイルを修正し、2つのモデルの関連付けを行います。
(app/models/user.rb)
class User < ApplicationRecord
has_many :items
end
(app/models/item.rb)
class Item < ApplicationRecord
belongs_to :user
end
サーバーを起動し、ブラウザで「localhost:3000/users」「localhost:3000/items」にアクセスすると、以下のように表示されます。
form_withヘルパーの確認
では、フォームを表示するためのViewファイルapp/views/users/_form.html.erbを確認していきましょう。1行目にform_withが使用されています。
(app/views/users/_form.html.erb)
<%= form_with(model: user, local: true) do |form| %>
・・・
<% end %>
form_withヘルパーには、複数のオプションが準備されていますが、scaffoldでは「:model」オプションと「:local」が使われています。
オプション
「:local」オプションは、submitによるデータ送信にAjaxを使わないことを示すオプションです。旧バージョンのform_forヘルパーでは、デフォルトでAjaxを使うことがありませんでしたので、それに合わせて使用しないように設定しています。(このオプションについては、Form_withヘルパーの本質とはずれますので、説明はここまでにします)
「:model」オプションは、生成するフォームがどのモデルに基づいて作られるかを示すオプションです。form_forヘルパーの第1引数と同じですので、このモデルから推測された送信先へ送信するフォームが生成されます。
具体的には、以下のようなフォームが生成されています。
<form action=”/users” method=”post”>
・・・
</form>
※なお、実際には、過去のブラウザ(IE5以前)での文字化け防止のための「accept-charset」属性や非表示(Hidden属性)のUTF-8タグ、CSRF(クロスサイト・スクリプト・フォージェリ)攻撃対策の非表示タグも生成されていますが省略しています
生成されたHTMLでは、HTTPリクエストが「POST」、送信先URLが「/users」に設定されています。
フォームIDとクラス属性
form_withの導入によって、Rails5.1では、フォームID(id)とクラス属性(class)は自動付与されなくなっています。上述しているHTMLにも、「id=」と「class=」が付与されていません。そのため、フォームIDとクラス属性は自分で付与しなければいけなくなりました。
※Rails5.2で自動付与されるように変更されましたので、バージョン5.2以降を使っている人は、自分で付与する必要はありません
その対策の一環として、HTML属性の設定について、form_forヘルパーと設定方法が違っています。
form_forヘルパーでは、HTML属性は、すべて「:html」オプションで設定しなければいけませんでしたが、ID属性とクラス属性、それにdata属性については、その必要はなくなり、それぞれ「:id」オプション、「:class」オプション、「:data」オプションが新設されています。
・form_forヘルパーの場合
<%= form_for(user, html:{class: “new_user”, id: “new_user”, data:{guest: “normal”}}) do |form| %>
・form_withヘルパーの場合
<%= form_with(model: user, local: true, class: “new_user”, id: “new_user”, data:{guest: “normal”}) do |form| %>
どちらでも、以下のHTMLが生成されます。
<form id=”new_user” class=”new_user” data-guest=”normal” action=”/users” method=”post”>
ブロック引数form
form_withヘルパーのブロック引数formは、モデルオブジェクトの情報を保持するFormBuilderオブジェクトであるのは、form_forヘルパーと同じです。
また、フォームコントロールを生成するためのメソッドについても、FormBuilderオブジェクト及び、その親クラスであるHelperを継承しているFormHelperやFormTagHelperのメソッドも使用できます。これも、form_forヘルパーと同じです。
form_withヘルパーとform_forヘルパーの違い
ここまでに確認したものも含めて、form_withヘルパーがform_forヘルパーと違っているところをまとめておきましょう。
モデルを指定するために、「:modelオプション」を利用する |
submitによるデータ送信に、デフォルトでAjaxを使う(リモートフォームがオンになっている) |
classとidが自動付与されない(Rails5.2以降であれば自動付与される) |
「:class」「:id」「:data」の3つのオプションが新設され、これらは「:html」オプションで設定する必要がない |
モデルに基づかないフォームを生成できる |
テーブルにカラムがないフォームフィールドを扱える |
これらの違いを踏まえれば、form_withヘルパーは、今までのform_forヘルパーとまったく同じように扱うことができます。
事実、以下のように変更すれば、何の問題もなく同じ動作をします。(新規作成や編集が何の問題もなく通常通りできます)
(app/views/users/_form.html.erb)
・変更前
<%= form_with(model: user, local: true) do |form| %>
・変更後
<%= form_for(user) do |form| %>
その他のform_withヘルパーの機能
scaffoldで自動生成されていないため、ここまでに紹介できていない、以下の2つの機能を紹介しましょう。
・モデルに基づかないフォームを生成できる
・テーブルにカラムがないフォームフィールドを扱える
それぞれ、詳しく説明します。
モデルに基づかないフォームの生成
form_withヘルパーにあって、form_forヘルパーにはなかった機能の1つのが、この「モデルに基づかないフォーム」の生成です。
じつは、この機能はform_tagヘルパーというform_forヘルパーと同時に非推奨になったヘルパーの機能で、これらの統合が、form_withヘルパーの大きな目的の1つだったとも言えます。
詳細は後述するとして、「モデルに基づかないフォーム」をテスト環境に追加してみましょう。
form_withヘルパーのオプション指定で:modelオプションを利用しなければ、モデルに基づかないフォームを生成することになります。
しかし、当然ですがモデルからの推測ができませんので、:urlオプションの指定が必要です。しかし、そうなると送信先が固定となりますので、用途は限られてくるでしょう。
例えば、検索フォームなどで利用します。
実際に一覧表示にTitleを検索する検索フォームを追加してみます。なお、新たな動作を追加するためには、View、モデル、コントロールの3つすべてに、追加や変更が必要ですので、憶えておきましょう。
Viewの変更
(app/views/items/index.html.erb)
<%= notice %>
<div id=”input-search”>
<%= form_with(url: items_path, method: :get, local: true) do |f| %>
<%= f.text_field :search %>
<%= f.submit “search” %>
<% end %>
</div>
<h1>Items</h1>
:
まず、一覧表示のViewファイルであるindex.html.erbに、検索フォームを追加します。ここで、:modelオプションの指定をやめて、「モデルに基づかないフォーム」としています。
ただし、その代わりに:urlオプションでデータの送付先(画面遷移先)を指定しています。今回は、一覧画面で表示するリストを検索するフォームですので、検索結果を表示するため、データ送付先は一覧画面(items_path:localhost:3000/items)にしています。
また、HTTPリクエストについても、:methodオプションで「GET」に指定しています。(指定しなければ「POST」になるため)
なお、検索文字列入力用のフォームコントロールは「f.text_field」です。引数の「:search」が、入力された文字列を格納するparamsハッシュのキーです。
モデルの変更
(app/models/item.rb)
class Item < ApplicationRecord
belongs_to :user
# Search method(add search)
def self.search(title)
if title
Item.where([‘title LIKE ?’, “%#{title}%”])
else
Item.all
end
end
end
次に検索処理の本体をモデルファイルに実装します。
今回はitemモデル内を検索しますので、itemモデルのファイルに、検索用のメソッド「search」を追加します。検索する実態はDBであり、モデルは処理だけ提供しますので、クラスメソッドとして実装しています。
引数として、検索フォームに入力された文字列を受け取り、文字列が何かあれば、whereメソッドで検索を行います。(その文字列とItemモデルのtitleカラムと部分一致するものを取得)なければ、今まで通り全データを取得するようにしています。
コントロールの変更
(app/controllers/items_controller.rb)
:
def index
# @items = Item.all
@items = Item.search(params[:search]) # (1)item data from Search View
end
:
コントローラでは、全データ取得の部分を削除して、モデルファイルに追加したsearchメソッドを呼ぶ処理を追加します。このときに渡す引数は、フォームから受け取った値です。
モデルに基づかないフォームの場合、入力されたデータがparamsハッシュに格納されていますので、フォームで指定したキーに基づいて、取得しています。
なお、モデルに基づいたフォームの場合、params[モデル名][キー]になりますので、注意してください。
実行結果
以上の変更を行ったあと、改めて「localhost:3000/items」にアクセスしてみましょう。
先頭に検索フォームが追加されていますので、そこに「r」と入力して検索してみましょう。すると、以下のようにtitleに「r」が含まれているものだけが表示されます。
テーブルにカラムがないフォームフィールド
form_forでは、基づいているモデルのテーブルにカラムがないフォームフィールドは扱えませんでした。
しかし、form_withヘルパーでは、paramsハッシュに問題なく追加され、コントローラへ送られます。
実際に試してみましょう。
(app/views/users/_form.html.erb)
:
<div class=”field”>
<%= form.label :user_id %>
<%= form.number_field :user_id %>
</div>
<!– add(1) –>
<div class=”field”>
<label>Don’t have field</label>
<%= form.text_field :test_string %>
</div>
<!– add(1) –>
<div class=”actions”>
<%= form.submit %>
</div>
<% end %>
「add(1)」に挟まれているテキストフィールドを追加してみてください。
「localhost:3000/items/new」にアクセスしてみると、form_withヘルパーの場合は以下のように正常に動作します。(form_forヘルパーではエラーになってしまいます)
登録しても、「Don’t have field」フィールドに入力した文字列は保存されませんが、コントロールからparams[:item][:test_string]でアクセス可能です。
“未経験”でもたった1ヶ月で営業からエンジニアとして転職!『WebCamp』受講者インタビュー
form_withヘルパーの詳細情報
では、ここからは「form_withヘルパー」の構文やオプションなどの詳細を紹介していきましょう。
構文は憶えたほうが良いですが、オプションをすべて憶える必要はありません。わからなくなれば、また本記事を確認していただければ幸いです。
構文
form_with(オプション) do |f|
フォームコントロールの設置
end
オプションには、以下があります。
オプション | 説明 | デフォルト値 |
---|---|---|
:url | フォームに入力されたデータを送信するURL。名前付きルートを直接使用可能 | nil |
:method | HTTPリクエスト(HTTPメソッド)の指定。 | POST |
:format | 送信するデータ形式 JSON形式やXML形式など :urlオプションが指定された場合は無視される |
text/html |
:scope | ルーティングで名前空間が指定されている場合に利用するプレフィックス指定 | nil |
:model | モデルオブジェクト オブジェクトが新規レコードの場合は作成フォームが生成され、既存レコードの場合は更新フォームが生成される |
nil |
:authenticity_token | 認証トークンの指定。 カスタム認証トークンでオーバーライドするかfalse、認証トークンフィールドをスキップします。 |
|
:local | リモートフォームを使わない設定 | false |
:skip_enforcing_utf8 | IE5以前の文字化け対策(UTF-8の矯正送信)のスキップ設定 | false |
:builder | フォームオブジェクトのオーバーライド(オリジナルフォームコントロールの作成) | nil |
:id | オプションのHTML id属性 | nil |
:class | オプションのHTMLクラス属性 | nil |
:data | オプションのHTMLデータ属性 | nil |
:html | id、class、data以外のオプションHTML属性 | nil |
https://web-camp.io/magazine/archives/12654
まとめ
form_withヘルパーについて、説明しました。form_withヘルパーは、Rails5.1 から導入された新しいヘルパーですので、あまり情報がないかもしれません。しかし、これまで使ってきたform_forヘルパーやform_tagヘルパーの代替えとして、これらの機能を統合して使いやすくしたヘルパーです。今後、新たにRailsアプリケーションの開発を行うときに、知らなければ時代遅れになりますので、今のうちにしっかりと学習しておくことをおすすめします。
・form_withヘルパーは、Rails5.1で導入されたフォームを生成するヘルパー
・form_withヘルパーの導入に伴って、form_forヘルパーとform_tagヘルパーは非推奨になった
・form_withヘルパーは、モデルを指定するために、「:modelオプション」を利用する
・form_withヘルパーは、submitによるデータ送信に、デフォルトでAjaxを使う(リモートフォームがオンになっている)
・form_withヘルパーは、classとidが自動付与されない(Rails5.2以降であれば自動付与される)
・form_withヘルパーでは、モデルに基づかないフォームを生成できる
・form_withヘルパーでは、テーブルにカラムがないフォームフィールドを扱える
【インタビュー】1ヶ月でRubyをゼロから学び、Webエンジニアとして転職!
ブラジルから帰国し技術をつけようとRubyエンジニアを目指してWebCampでRubyを学び、見事Webエンジニアとして転職を果たした田中さんにお話を伺いました。
「Rubyの学習がしたい。基礎をしっかりと理解したい」
「転職のサポートがほしい」
と考えている方はぜひお読み下さい。
https://web-camp.io/magazine/archives/8535
また、エンジニア転職は考えていないけれど、プログラミング学習を本気でしたい方はDMM WEBCAMPのSKILLSコースがおすすめです!
無料説明動画が公式ページにありますので、そちらをご覧になってみてください。