Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

[Rails 4][Rails 5] 'form_for' APIドキュメント完全翻訳

注意: Rails 5.1以降はform_withが推奨され、form_forform_tag非推奨になりました。

Rails 5.1〜7.0: ‘form_with’ APIドキュメント(翻訳)


こんにちは、hachi8833です。

Rails 4および5のform_forメソッドのAPIドキュメントをすべて翻訳いたしました。
Rails 3のform_forメソッドのAPIドキュメント翻訳については以下をご覧ください。

概要

Rails 3、4、5のform_forメソッドを最新の公式APIドキュメントでチェックしてみたところ、現時点でのRails 4とRails 5向けform_forメソッドのAPIドキュメントは完全に一致していました。また、Rails 3とRails 4/5のドキュメントの差分もさほどありませんでした。

なお、form_forform_tagは今後form_withで一元的に利用できるようになるとのことです。

追伸: その後form_withが公開されましたので、Rails 5.1以降はこちらを使うことをおすすめします。

form_for (Rails 4およびRails 5)

#API呼び出し(Rails 3、4、5共通)
form_for(record, options = {}, &block)

特定のモデルオブジェクトの属性をユーザーが作成、更新できるフォームを作成します。

form_forメソッドは、フォームの構成をRailsにどの程度まで自動的に推測させたいかに応じて、さまざまな方法で用いることができます。一般的なモデルオブジェクトの場合、扱いたいオブジェクトを表す文字列やシンボルを以下のようにform_forに渡すことでフォームを作成できます。

<%= form_for :person do |f| %>
  First name: <%= f.text_field :first_name %><br />
  Last name : <%= f.text_field :last_name %><br />
  Biography : <%= f.text_area :biography %><br />
  Admin?    : <%= f.check_box :admin %><br />
  <%= f.submit %>
<% end %>

ブロックの変数fは、form_forに渡される:personが指すモデルオブジェクトに関する情報を保持するFormBuilderオブジェクトです。FormBuilderで定義されているメソッドは、このモデルに紐付けられるフィールドの生成に使われます。

<%= f.text_field :first_name %>

たとえば、上のコードは以下のように展開されます。

<%= text_field :person, :first_name %>

展開されたコードからHTML<input>タグが生成されます。このタグのname属性はperson[first_name]になります。これにより、フォームが送信されると、ユーザーの入力した値はコントローラでparams[:person][:first_name]という形でアクセスできるようになります。

FormBuilderで生成されたフィールドは次のような性質を持ちます。たとえば:personがたまたま@personインスタンス変数でもある場合には、フォームを最初にユーザーが表示したとき(ユーザーが既存のレコードを編集中の場合など)に表示されるデフォルト値には、@personの属性に対応する値が使われます。

form_forの一番右(ブロックを除く)の引数はオプションハッシュであり、以下のオプションを利用できます。

:url
フォームの送信先URLです。この引数はurl_forlink_toに渡される値と同じ方法で表現できますので、名前付きルートを直接利用できます。上記のようにモデルを文字列やシンボルで表し、かつ:urlオプションを指定しない場合、フォームの送信先はデフォルトで現在のURLになります。なお、後述するform_forのリソース指向の利用法では、URLを明示的に使用する必要がありません。
:namespace
フォーム要素のid属性を一意にするための名前空間を指定します。名前空間の属性の前には、生成されたHTML idの後ろにアンダースコア_を付けたものが追加されます。
:method
フォームの送信方法を指定します。
* getpost: 通常はこれを使います。
* patchputdelete: これらを使うと、postでこのverbをシミュレートするために、_methodを付けた名前がフォームのinputに非表示で追加されます。
:authenticity_token
フォームが本物であることを示すトークンです。
カスタムトークンを渡したい場合や、あえて:authenticity_tokenfalseを指定してトークンを無効にする以外の目的では使わないでください。
config.action_view.embed_authenticity_token_in_remote_forms = falseを設定で指定することで、リモートフォームでのトークン埋め込みを省略できます。このオプションは、フォームでフラグメントキャッシュを行う場合に有用です。リモートフォームはトークンをmetaタグで受け取るようになるので、JavaScriptが使えないブラウザをサポートしない場合にもトークンの埋め込みが不要になります。
:remote
trueを指定すると、送信の挙動をUnobtrusive JavaScript(控えめなJavaScript)で制御できるようになります。デフォルトではAjax送信になります。
:enforce_utf8
falseを指定すると、utf8という名前の非表示inputを出力しなくなります。
:html
フォームのタグにHTML属性を追加するのに使います。

form_forは排他的なスコープを作成しないことにご注意ください。排他的なスコープの作成は、単独のFormHelperのメソッドとFormTagHelperのメソッドを両方使えば可能です。次の例をご覧ください。

<%= form_for :person do |f| %>
  First name: <%= f.text_field :first_name %>
  Last name : <%= f.text_field :last_name %>
  Biography : <%= text_area :person, :biography %>
  Admin?    : <%= check_box_tag "person[admin]", "1", @person.company.admin? %>
  <%= f.submit %>
<% end %>

上の方法は、オブジェクトをベースとする設計になっているFormOptionHelperやDateHelperのメソッドでも使えます(FormOptionHelper#collection_selectActionView::Helpers::DateHelper#datetime_select)。

form_forをモデルオブジェクトで使う

上の例では、作成または編集されるオブジェクトはシンボルとして表現されて#form_forに渡されていますが、文字列でも同様に渡せます。また、前述のとおり#form_forにはモデルオブジェクト自身も渡せます。たとえば、フォームで編集したい既存のレコードが@postである場合、以下のようにしてフォームを作成できます。

<%= form_for @post do |f| %>
  ...
<% end %>

このようにして作成したフォームの挙動は、前述の方法とほぼ同じですが、若干異なる点があります。

第一に、フォーム内の1つまたは複数のinput要素(これらはparamsハッシュのキーになります)に付けられる名前のプレフィックスは、そのオブジェクトのクラスから引用されます。たとえば、Postというクラスであればparams[:post]となります。:asオプションを使うと、たとえば以下のようにプレフィックスを上書きできます。

<%= form_for(@person, as: :client) do |f| %>
  ...
<% end %>

上のコードではparams[:client]を得られます。

第二に、フォームで最初に表示されるフィールドの値には、form_forに渡されるオブジェクトの属性が使われます。この挙動は、オブジェクトがインスタンス変数であるかどうかにかかわらず同じです。したがって、たとえばpostという「ローカル」変数があり、それが既存のレコードを表す場合は次のようになります。

<%= form_for post do |f| %>
  ...
<% end %>

上のコードで最初に表示されるフォームには、ローカル変数postの属性の現在の値が反映されます。

リソース指向のスタイル

ここまでのコード例には明示的に書かれていませんでしたが、実際には:urlオプションでフォームの送信先を指定する必要があります。ただし、#form_forに渡されるレコードがリソースの場合は、フォームの送信先はもっと簡単に指定できます。

たとえば、対応するRESTfulなルーティングのセットがある(つまりconfig/routes.rbでリソースとして定義されている)場合が該当します。

Railsではこのような場合、最適なURLを次のようにレコード自身から推測します。

<%= form_for @post do |f| %>
  ...
<% end %>

上のコードは、以下のようなコードと同等です。

<%= form_for @post, 
             as: :post,
             url: post_path(@post),
             method: :patch,
             html: { class: "edit_post", id: "edit_post_45" } do |f| %>
  ...
<% end %>

新規レコードの場合は以下のように書けます。

<%= form_for(Post.new) do |f| %>
  ...
<% end %>

上のコードは、以下のようなコードと同等です。

<%= form_for @post,
             as: :post,
             url: posts_path,
             html: { class: "new_post", id: "new_post" } do |f| %>
  ...
<% end %>

これらは次のように上書きできます。

<%= form_for(@post, url: super_posts_path) do |f| %>
  ...
<% end %>

送信フォーマットも次のように指定できます。

<%= form_for(@post, format: :json) do |f| %>
  ...
<% end %>

admin_post_url:のような名前空間化されたルーティングの場合は次のように書けます。

<%= form_for([:admin, @post]) do |f| %>
 ...
<% end %>

リソースに何らかの関連付けが定義されている場合は、ルーティングが正しく設定されているdocumentに次のようにcommentを追加できます。

<%= form_for([@document, @comment]) do |f| %>
 ...
<% end %>

なお、上のコードでは@document = Document.find(params[:id])および@comment = Comment.newが設定されていることが前提です。

メソッドを設定する

オプションハッシュ内に次のように書くと、HTTP verbの完全な配列をフォームに渡して強制的に使うように設定できます。

method: (:get|:post|:patch|:put|:delete)

こうすると、GETPOST(これらはHTMLフォームでネイティブでサポートされます)でないverbが使われた場合に、フォームでPOSTが設定され、_methodと呼ばれる非表示のinputによって、サーバーが解釈できる期待どおりのverbが実行されます。

「控えめなJavaScript」によるAjax

オプションハッシュで以下を指定すると、いわゆる「控えめな(unobtrusive)JavaScript」のドライバでフォームの挙動を変更できます。

remote: true

このオプションを指定した場合のデフォルトの挙動では、通常のPOSTではなくXMLHttpRequestがバックグラウンドで動作することが期待されますが、最終的な動作はJavaScriptドライバの実装によって決定されます。

仮にフォームのさまざまな要素をJavaScriptによってシリアライズした場合でも、フォームを受信する側(つまりサーバー)から見ると通常の送信と同じ挙動になり、すべての要素をparamsで受け取れます。

次のコード例をご覧ください。

<%= form_for(@post, remote: true) do |f| %>
  ...
<% end %>

上のERBによって次のHTMLが生成されます。

<form action='http://www.example.com' method='post' data-remote='true'>
  <input name='_method' type='hidden' value='patch' />
  ...
</form>

HTMLオプションを設定する

data-属性はdata:ハッシュで直接渡せますが、他のすべてのHTMLオプションについては次のようにhtml:ハッシュの中に置く必要があります。

<%= form_for(@post, 
             data: { behavior: "autosave" },
             html: { name: "go" }) do |f| %>
  ...
<% end %>

上のコードによって以下のHTMLが生成されます。

<form action='http://www.example.com' method='post' data-behavior='autosave' name='go'>
  <input name='_method' type='hidden' value='patch' />
  ...
</form>

非表示のモデルidを出力しないようにする

#form_forメソッドを使うと、自動的にモデルidが隠しフィールドとしてフォームに含まれます。このモデルidは、フォームデータとそれに関連付けられているモデルとの関連を保つために使われます。

ORMシステムによってはネストしたモデルでこうしたidを使わないものもあるので、その場合は次のようにinclude_id: falseを指定することで隠しフィールドのモデルidを出力しないようにできます。

<%= form_for(@post) do |f| %>
  <%= f.fields_for(:comments, include_id: false) do |cf| %>
    ...
  <% end %>
<% end %>

上の例では、NoSQLデータベースにPostというモデルがひとつと、それに一対多で関連付けられるCommentというモデルが保存されています。:commentsには主キーはありません。

フォームビルダをカスタマイズする

FormBuilderクラスをカスタマイズしてフォームをビルドすることもできます。カスタマイズするには、FormBuilderを継承してサブクラスを作り、必要なヘルパーメソッドを定義またはオーバーライドします。

次のコード例では、フォームのinputにラベルを自動追加するヘルパーを作成済みであることが前提です。

<%= form_for @person, url: { action: "create" }, builder: LabellingFormBuilder do |f| %>
  <%= f.text_field :first_name %>
  <%= f.text_field :last_name %>
  <%= f.text_area :biography %>
  <%= f.check_box :admin %>
  <%= f.submit %>
<% end %>

上のようにコードを書いてから、次のコードを書きます。

<%= render f %>

これにより、people/_labelling_formというテンプレートを使ってレンダリング(=HTML生成)され、ローカル変数fが参照するフォームビルダの名前はlabelling_formとなります。

特に指定しない限り、カスタムのFormBuilderクラスは、ネストした#fields_for呼び出しのオプションと自動的にマージされます。

上のようなコードを別のヘルパーにも含めておきたい場合は、以下のように書けます。

def labelled_form_for(record_or_name_or_array, *args, &block)
  options = args.extract_options!
  form_for(record_or_name_or_array, *(args << options.merge(builder: LabellingFormBuilder)), &block)
end

モデルのインスタンスにフォームをアタッチする必要がない場合は、ActionView::Helpers::FormTagHelper#form_tagを参照してください。

外部リソースを使うフォーム

外部リソース(認証トークンの設定が必要な場合や、認証なしでフォームだけ表示したい場合などを含む)を扱うフォームをビルドする場合を考えてみましょう。何らかの支払い用ゲートウェイ番号にデータを送信しなければならず、フィールドの種類にも制限があるとします。

必要な認証トークンを渡すには、:authenticity_tokenオプションを使います。

<%= form_for @invoice, 
             url: external_url, 
             authenticity_token: 'external_token' do |f| %>
  ...
<% end %>

認証トークンを一切出力したくない場合は、単にfalseを渡します。

<%= form_for @invoice,
             url: external_url,
             authenticity_token: false do |f|  %>
  ...
<% end %>

関連記事

[Rails 3] ‘form_for’ APIドキュメント完全翻訳

Rails: ビューのHTMLエスケープは#link_toなどのヘルパーメソッドで解除されることがある


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。