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

こんにちは、hachi8833です。先週リリースされたRails 5.1の目玉機能のひとつである#form_withのAPIドキュメントを翻訳いたしました。

概要

原文の更新や訳文の誤りにお気づきの方は、ぜひフォームまたは@techrachoまでお知らせください。

参考

Rails 5.1 #form_with APIドキュメント(翻訳)

# API呼び出し
form_with(model: nil, scope: nil, url: nil, format: nil, **options)

URL、スコープ、モデルの組み合わせを元にformタグを作成します。

URLのみを指定する

<%= form_with url: posts_path do |form| %>
  <%= form.text_field :title %>
<% end %>

# =>
<form action="/posts" method="post" data-remote="true">
  <input type="text" name="title">
</form>

inputフィールド名にスコープのプレフィックスを追加する

<%= form_with scope: :post, url: posts_path do |form| %>
  <%= form.text_field :title %>
<% end %>

# =>
<form action="/posts" method="post" data-remote="true">
  <input type="text" name="post[title]">
</form>

渡されたモデルからURLとスコープを自動推測する

<%= form_with model: Post.new do |form| %>
  <%= form.text_field :title %>
<% end %>

# =>
<form action="/posts" method="post" data-remote="true">
  <input type="text" name="post[title]">
</form>

既存のモデルを更新するフォームで、モデルの値をフィールドに表示する

<%= form_with model: Post.first do |form| %>
  <%= form.text_field :title %>
<% end %>

# =>
<form action="/posts/1" method="post" data-remote="true">
  <input type="hidden" name="_method" value="patch">
  <input type="text" name="post[title]" value="<postのtitle>">
</form>

フォームのフィールドは、必ずしもモデルの属性と対応してなくてもよい

<%= form_with model: Cat.new do |form| %>
  <%= form.text_field :cats_dont_have_gills %>
  <%= form.text_field :but_in_forms_they_can %>
<% end %>

# =>
<form action="/cats" method="post" data-remote="true">
  <input type="text" name="cat[cats_dont_have_gills]">
  <input type="text" name="cat[but_in_forms_they_can]">
</form>

フォームのパラメータは、コントローラでパラメータのネストに沿ってアクセスできます。つまり、inputフィールドにtitlepost[title]というフィールド名がある場合、コントローラではそれぞれparams[:title]params[:post][:title]としてアクセスできます。

フォームのinputフィールド名 コントローラのparams
title params[:title]
post[title] params[:post][:title]

#form_withにはデフォルトでdata-remote属性が追加され、rails-ujsなどのunobtrusive JavaScript(控えめなJavaScript)ドライバが使われている場合はバックグラウンドでXMLHTTPRequest経由でフォームを送信します。詳しくは:localオプションをご覧ください。

なお、上の例では比較しやすさのため送信ボタンを省略しています。また、UTF-8サポート用に自動生成される隠しフィールドや、CSRF(クロスサイト・スクリプト・フォージェリ)攻撃からの保護のために自動追加される認証トークンも省略しています。

#form_withで利用できるオプション

:url
フォームの送信先URLを指定します。
渡せる値は、url_forlink_toで渡せる値と似ています。たとえば、名前付きルートを直接渡すこともできますし、:urlなしで:scopeを渡すと、現在のURLにフォームを送信することもできます。
:method
フォーム送信時のHTTPメソッド(verb)を指定します。
通常は:get:postを指定します。
:patch:put:deleteを指定すると、隠しinput名の後ろに_methodが追加され、POST verb上でこれらのHTTP verbをシミュレートします。
:format
フォーム送信先であるルーティングのフォーマットを指定します。
:jsonなど通常と異なるリソースタイプを送信するのに便利です。
:urlがオプションに渡されている場合、このオプションはスキップされます。
:scope
inputフィールド名のプレフィックスにスコープを追加します。これにより、送信されたパラメータをコントローラでグループ化できます。
:model
:url:scopeの自動推測に使うモデルオブジェクトを指定し、inputフィールドにモデルの値を表示します。
たとえば、title属性の値が"Ahoy!"ならtitleの入力フィールドの値に"Ahoy"と表示されます。
モデルが新しいレコードの場合は作成用フォームが生成され、モデルが既存のレコードの場合は更新用フォームが生成されます。
デフォルトの動作を上書きするには、:scope:urlを渡します(params[:post]params[:article]に変更するなど)。
:authenticity_token
フォームで使う認証トークンを指定します。
カスタムの認証トークンを指定して上書きすることも、falseを渡して認証トークンのフィールドをスキップすることもできます。
有効なフィールドのみに制限されている支払用ゲートウェイへのような外部リソースにフォームを送信する場合に便利です。

config.action_view.embed_authenticity_token_in_remote_forms = falseを指定すると、埋め込み認証トークンがリモートフォームで省略されることがあります。この指定はフォームでフラグメントキャッシュを使う場合に便利です(リモートフォームがmetaタグから認証トークンを取得するようになるので、JavaScriptがオフになっているブラウザをサポートする場合を除けば認証トークンをフォームに埋め込む必要がなくなります)。
:local
local: trueを指定するとフォームのリモート + unobtrusive XHR送信が無効になります(デフォルトのフォームではリモート + unobtrusive XHRが有効になります)。
:skip_enforcing_utf8
trueを指定すると、送信時にutf8という隠しフィールドがスキップされます(デフォルトの送信ではutf8フィールドが出力されてエンコードがUTF-8になります)。
:builder
フォームのビルドに使うオブジェクトをオーバーライドします。
:id
HTMLのid属性を指定します(オプション)。
:class
HTMLのclass属性を指定します(オプション)。
:data
HTMLのdata属性を指定します(オプション)。
:html
上以外のHTML属性を使う場合に指定します(オプション)。

#form_withにブロックを渡さない場合は、開始formタグを生成します。

# 名前付きパスを指定する場合
<%= form_with(model: @post, url: super_posts_path) %>

# スコープを追加する場合
<%= form_with(model: @post, scope: :article) %>

# フォーマットを指定する場合
<%= form_with(model: @post, format: :json) %>

# トークンを無効にする場合
<%= form_with(model: @post, authenticity_token: false) %> 

ルーティングをadmin_post_urlのような名前空間化する場合は以下のようにします。

<%= form_with(model: [ :admin, @post ]) do |form| %>
  ...
<% end %>

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

<%= form_with(model: [ @document, Comment.new ]) do |form| %>
  ...
<% end %>

上のdocumentには@document = Document.find(params[:id])が既に与えられているとします。

#form_withでラベルを表示する場合、フィールドのid:にラベルを設定する必要があります。

<%= form_with(model: @post) do |form| %>
  <%= form.label :title %>
  <%= form.text_field :title, id: :post_title %>
<% end %>

for属性の導出方法についてはlabelを参照してください。

他のフォームヘルパーと組み合わせる

#form_withではFormBuilderオブジェクトが使われていますが、単独のFormHelperのメソッドやFormTagHelperのメソッドと共存させることもできます。

<%= form_with scope: :person do |form| %>
  <%= form.text_field :first_name %>
  <%= form.text_field :last_name %>

  <%= text_area :person, :biography %>
  <%= check_box_tag "person[admin]", "1", @person.company.admin? %>

  <%= form.submit %>
<% end %>

同様に、FormOptionHelperのメソッド(FormOptionHelper#collection_selectなど)と共存させたり、DateHelperのメソッド(ActionView::Helpers::DateHelper#datetime_selectなど)と共存させることもできます。

HTTPメソッド(verb)の指定方法

以下のHTTP verbの完全な配列をoptionsハッシュに渡すことができます。

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

verbがGETPOST以外の場合(この2つはHTMLフォームでネイティブでサポートされます)、フォームそのものにはPOST verbが設定され、_methodという名前の隠しinputフィールドには指定の verbが設定され、後者がサーバーで解釈されます。

HTMLオプションの設定方法

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

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

上のコードから以下のHTMLが生成されます。

<form action="/posts/123" 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_with(model: @post) do |form| %>
  <%= form.fields(:comments, skip_id: true) do |fields| %>
    ...
  <% end %>
<% end %>

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

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

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

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

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

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

<%= render form %>

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

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

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

def labelled_form_with(**options, &block)
  form_with(**options.merge(builder: LabellingFormBuilder), &block)
end

関連記事

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833 コボラー、ITコンサル、ローカライズ業界を経てなぜかWeb開発者志願。 これまでにRuby on Rails チュートリアルの大半、Railsガイドのほぼすべてを翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

Rubyスタイルガイドを読む

BigBinary記事より

ActiveSupport探訪シリーズ