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

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

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

Rails 5.1〜7.0: ‘form_with’ 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_withが公開されましたので、Rails 5.1以降はこちらを使うことをおすすめします。

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が実行されます。

「控えめな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 %>

関連記事

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

Railsでフォームオブジェクトを使った検索を簡単に実装する方法

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


CONTACT

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