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

こんにちは、hachi8833です。

Rails 3のform_forメソッドのAPIドキュメントをすべて翻訳いたしました。
Rails 4および5の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_for (Rails 3)

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

フィールドの値をユーザーに問い合わせるための特定のモデルオブジェクトを元に、フォームとスコープを作成します。

Railsのform_forを以下のように使って、簡潔な「リソース指向フォーム」を生成できます。

<%= form_for @offer do |f| %>
  <%= f.label :version, 'Version' %>:
  <%= f.text_field :version %><br />
  <%= f.label :author, 'Author' %>:
  <%= f.text_field :author %><br />
  <%= f.submit %>
<% end %>

form_forは、レコードのイントロスペクションに基づいたRESTfulなフォームパラメータを生成できます。しかし、この動作を理解するにはform_forの基本となる別の一般的な用法についてまず知っておく必要があります。

一般的な#form_for

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.text_field :first_name %>

上のコードは以下のように展開されます。

<%= text_field :person, :first_name %>

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

:url
フォームの送信先URLです。ここにはurl_forlink_toに渡すのと同じフィールドを渡せます。名前付きルートを直接渡すこともできます。デフォルトは現在のアクションです。
:namespace
フォーム要素のid属性を一意にするための名前空間を指定します。名前空間の属性の前には、生成されたHTML idの後ろにアンダースコア_を付けたものが追加されます。
: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]", @person.company.admin? %>
  <%= f.submit %>
<% end %>

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

リソース指向のスタイル

前述のとおり、#form_for呼び出しは手動で設定できるほか、命名規則や名前付きルーティングに基いてリソースを自動識別することもできます。現在の#form_forは、手動よりも自動化された方法で使うことが推奨されています。

たとえば、編集したい既存のレコード@postがあるとします。

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

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

<%= form_for @post, 
             :as => :post,
             :url => post_path(@post), 
             :method => :put,
             :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 %>

オブジェクトのパラメータを別の方法で表す必要がある場合は次のようにします。ここではPersonClientとして扱っています。

<%= form_for(@person, :as => :client) 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|:put|:delete)

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

in the options hash. If the verb is not GET or POST, which are natively supported by HTML forms, the form will be set to POST and a hidden input called _method will carry the intended verb for the server to interpret.

「控えめな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'>
  <div style='margin:0;padding:0;display:inline'>
    <input name='_method' type='hidden' value='put' />
  </div>
  ...
</form>

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

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

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

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

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

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

<%= 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 %>

関連記事

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探訪シリーズ