2020-12-13に更新

【第2回】基本的なフォームを作成する

概要

フォームヘルパーのヘルパーって?

  • この勉強をしたいと思ったのは、フォームについて勉強したいと思ったから
  • とはいえ、Railsガイドのタイトルは「Action View フォームヘルパー」
    • ということで、まずヘルパーについて簡単に触れる

Viewフォームヘルパーとは、ControllerやModelではなく、Viewで使うことを想定して、フォームを簡単かつ便利に作るためのヘルパー(道具)のこと。

例えば、content_tagヘルパーというものがあるのだけれど、これはまさにその典型例。

content_tag(:div, "header", class: ["one", "two"])
#=> "< div class="one two" >header< /div >"

という観点からすれば、フォームヘルパーとは、

  • フォームを簡単かつ便利に作るためのヘルパー(道具)のこと。

ということは、ヘルパー全般に言えるけれども、簡単かつ便利になる前の
HTMLタグたちを理解しなければ、フォームヘルパーの意味は理解できないとうこと。

基本的なフォームを作成する

Railsガイドでは、まずform_tagの説明から始まる。
ここで、form_tag, form_for, form_withの概要を確認する。

ということで、まずはform_forというモデルに紐づけないシンプルなケースを確認しよう。今では、form_withで書くことが一般的なので、その場合も確認する。

# form_tag
<%= form_tag do %>
  Form contents
<% end %>

# form_with
<%= form_with do %>
  Form contents
<% end %>
<!-- Railsガイドで紹介されていたHTML -->
<form accept-charset="UTF-8" action="/home/index" method="post">
  <div style="margin:0;padding:0">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
  </div>
  Form contents
</form>

<!-- Rails 6系で試した場合、すこし違うHTMLが出力された -->
<form action="/" accept-charset="UTF-8" method="post">
  <input type="hidden" name="authenticity_token" value="E3gz0DuIaaH2ah/jibBQN5pOw5fRWu/0EKopuZ3uCkpoxldUUdSGWt9fQeYnrtuRu0EwofSmrCSoQ3iSKmuwKQ==">
  Form contents
</form>

前回の記事で触れたとおりだが、以下を確認しよう。

  • action: フォームで送信するURL
  • method: HTTPのリクエストのメソッド(get, post, put, patch, deleteなど)
  • authenticity_token: CSRF対策のためのトークン。

なお、前回記事では触れなかったが、下記のとおりである。
そんなに重要ではないと思うけど一応確認する。

  • accept-charset: 文字コードを指定するオプション
  • name="utf8"のinput: 文字コードを指定するオプション
    • IEはフォームのaccpet_charsetを無視して、ブラウザの文字コードと同じエンコードだと認識してたらしい
    • それを乗り越えるため、隠しパラメータで文字コードを指定する方法を採用していたらしい

デフォルトでは、現在のURLに対してPOSTメソッドでHTTPリクエストが送られる。 なので、送信先のURLやメソッドに関する記述がなくとも、先ほどのようなHTMLタグが生成される。

1.1 一般的な検索フォーム

モデルに紐づかないフォームとしてありがちなのが、検索フォームだ。
この場合、actionやmethodがデフォルトのままだと困るので、設定する必要がある。

また、検索フォームの場合、何のフォームであるか示すため、
左横なんかにラベルがついていることが一般的だと思う。

そして、当然検索ワードを入力するtextなどの入力フォームや送信ボタンが必要となる。

ということで、このような記述になる。
せっかくなので、form_withバージョンで書いてみる。

<%= form_with(url: "/search", method: "get") do %>
  <%= label_tag(:q, "Search for:") %>
  <%= text_field_tag(:q) %>
  <%= submit_tag("Search") %>
<% end %>
<form accept-charset="UTF-8" action="/search" method="get">
  <div style="margin:0;padding:0;display:inline">
    <input name="utf8" type="hidden" value="&#x2713;" />
  </div>
  <label for="q">Search for:</label>
  <input id="q" name="q" type="text" />
  <input name="commit" type="submit" value="Search" />
</form>

GETメソッドの場合、parameterはURLにくっつけるような形で送信される。
例えば、googleでmiketaと検索すると、以下のようなURLにリダイレクトされる。

[https://www.google.com/search?q=miketa&rlz=1C5CHFA_enJP891JP891&oq=miketa&aqs=chrome..69i57j69i59l2j69i60l4j69i65.551j0j15&sourceid=chrome&ie=UTF-8](https://www.google.com/search?q=miketa&rlz=1C5CHFA_enJP891JP891&oq=miketa&aqs=chrome..69i57j69i59l2j69i60l4j69i65.551j0j15&sourceid=chrome&ie=UTF-8)

不勉強なので詳しいことは分からないが、以下のようなパラメータが送られている。本筋から外れるのでこれ以上は踏み入らないが、各メソッドの違いを意識するとよい。

q: miketa  
rlz: 1C5CHFA-en....  
aqs: chrome..69i...  
sourceid: chrome
ie: UTF-8

1.2 フォームヘルパーの呼び出しで複数のハッシュを使う

Railsガイドには、以下のように書いてある。

form_tagヘルパーは2つの引数を取ります。
1つはアクションへのパスで、もう1つはオプションのハッシュです。

このハッシュには、フォーム送信のHTTPメソッドやHTMLオプション(フォーム要素のクラスなど)が含まれます。

引数とは、メソッドのカッコ内のやつです。

form_tag(引数はここだよ)

引数は、アクションへのパスとオプションのハッシュの2つなので、こうなる。

form_tag(
  第1引数 - アクションへのパス(paramsの送り先のURL), 
  第2引数 - オプションのハッシュ(GETなどのHTTPメソッドやhtmlタグ内のclassの指定など
)

第1引数についてはURLを直書きすることもできるが、users_pathのように書くこともできるし、controller: "people", action: "search"のように書くこともできる。

ただ、controller: "people", action: "search"を何気なく書くと、エラーになってしまう。例えば、以下のように書くとactionが第2引数と認識されるのでエラーになる。

form_tag(controller: "people", action: "search", method: "get", class: "nifty_form")

よって、ハッシュを使うとよい。

form_tag({controller: "people", action: "search"}, method: "get", class: "nifty_form")

余談:form_withの場合

ぶっちゃけあまりform_tagなんて使わないと思うので、
form_withについても理解しておきたい。

ということで、form_withメソッドについても調べてみた。

form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)

ここでRuby自体の理解が大事になるのだが、こういった引数の書き方はキーワード引数という。キーワード引数を指定をしないとき、デフォルトの設定が採用される。

例えば、root_pathへのフォームを作成する場合、このようなコードとなる。

<%= form_with url: root_path do |form| %>
  フォーム内容
<% end %>

この場合、例えばmodelについての引数は指定されていない。その場合、デフォルトのmodel:nilが採用される。他のオプションについても、同様である。

その他のオプション等が何を意味するかについては、長くなりそうなので、後ほどの機会で。

1.3 フォーム要素生成に使うヘルパー

分かりやすいので、そのまま掲載する笑

Railsには、〜フォーム要素を生成するためのヘルパーが多数用意されています。
これらの基本的なヘルパーは名前が_tagで終わっており (text_field_tagやcheck_box_tagなど)
それぞれただ1つの<input>要素を生成します。

ただ、どちらかというと、tagよりfieldの方が目にすることが多いかもしれない。
fieldについては、後ほど触れる。

続ける。

これらのヘルパーの1番目のパラメータは、inputの名前と決まっています。
・・・たとえば、フォームに<%= text_field_tag(:query) %>というコードが含まれていたとすると、
コントローラでparams[:query]と指定すればこのフィールドの値にアクセスできます。

少し具体的にみてみる。

<%= form_with url:root_path do %>
  <%= check_box_tag(:pet_dog) %>
  <%= label_tag(:pet_dog, "I own a dog") %>
  <%= check_box_tag(:pet_cat) %>
  <%= label_tag(:pet_cat, "I own a cat") %>
  <%= submit_tag("Search") %>
<% end %>

これで、こんなHTMLタグが生成される。

<form action="/" accept-charset="UTF-8" method="post">
  <input type="hidden" name="authenticity_token" value="R0qYMo0//9dA1ECJ6G6muSXd9JXgss5z7DLPn6mwJL889Py252MQLGnhHoxGcC0fBNIHo8VOjaNU2560HjWe3A==">
  <input type="checkbox" name="pet_dog" id="pet_dog" value="1">
  <label for="pet_dog">I own a dog</label>
  <input type="checkbox" name="pet_cat" id="pet_cat" value="1">
  <label for="pet_cat">I own a cat</label>
  <input type="submit" name="commit" value="Search" data-disable-with="Search">
</form>

そして、このフォームから送信されたparamsを取得するには、
〜tagの第1引数を使って、こんな感じで書いてあげれば大丈夫。

# pet_dogにチェックを入れて、pet_catにチェックをしていない場合
params[:pet_dog] #=> 1という値が取得できる
params[:pet_cat] #=> nilになる(paramsが送られていないため)

1.4 その他のヘルパー

HTMLのinputタグは、山ほど種類がある。
20種類以上ある。

ということは、その数だけ、Railsのヘルパーもある。
Railsガイドでは、これだけ紹介されているが、あくまで一例。

<%= text_area_tag(:message, "Hi, nice site", size: "24x6") %>
<%= password_field_tag(:password) %>
<%= hidden_field_tag(:parent_id, "5") %>
<%= search_field(:user, :name) %>
<%= telephone_field(:user, :phone) %>
<%= date_field(:user, :born_on) %>
<%= datetime_local_field(:user, :graduation_day) %>
<%= month_field(:user, :birthday_month) %>
<%= week_field(:user, :birthday_week) %>
<%= url_field(:user, :homepage) %>
<%= email_field(:user, :address) %>
<%= color_field(:user, :favorite_color) %>
<%= time_field(:task, :started_at) %>
<%= number_field(:product, :price, in: 1.0..20.0, step: 0.5) %>
<%= range_field(:product, :discount, in: 1..100) %>

フォーム作成前に、どのようなinputタグがあるか、そしてそれに対応するrailsのヘルパーはどのようなものになるか、確認してみるといいかも。

最後にテスト

  • フォームヘルパーは、HTMLの何を簡単に作るものでしょう?
  • getメソッドの場合、パラメータはどこに付与されるでしょう?
    • ここではざっくりとしか説明してないですが、postメソッドの場合などについても調べてみるとよい
  • 以下の場合、どうすればいいでしょう?
    • emailフィールドのフォームを設ける
    • コントローラでparams[:person]として値を取得したい
    • モデルに紐づけず、検索フォームとしたい
    • 検索フォームは、emails_controller.rbのsearchアクションで処理する
    • 適当な設定なので、おかしいところがあるかもしれないが、ご容赦ください
    • その場合、ツッコミどころを考えるのも勉強になります笑
  • fieldの数を10個ぐらいあげてみよう!

補足

やばい、この調子だと日がくれる...


miketa_webprgr

31歳。元公務員。プログラマー目指して勉強中。欧州サッカー好き。なぜかバーンリー推し。

所有者限定モードのためこのボードには投稿できません
コメント