フォームヘルパー

Webアプリケーション内のフォームは、ユーザー入力にとって欠かせないインターフェースです。 ただし、フォームのマークアップ構築とメンテナンスは、フォームのコントローラー名とそれらの多すぎる属性のため、 すぐに冗長になりがちです。 Railsはこれらの複雑さを、ビューヘルパーのためのフォームのマークアップ生成を提供することで回避します。 ただし、それらは異なるユースケースを持つため、 これらを使用する前に開発者はこの同じようなヘルパーメソッドについての全ての違いを知っていおく必要があります。

このガイドを読むことで、次の事が学べるはずです。

  • アプリケーション内に、検索フォームとそれに類似した一般的なフォームを、特定のモデルを表さずに作成する方法について。
  • 特定のデータベースレコードの作成と編集のためのモデルが中心となるフォームの作成方法について。
  • 複数タイプのデータから、セレクトボックスの作成方法について
  • Railsが提供する日付・時間ヘルパーについて
  • ファイルアップロードのフォームの違いについて
  • 外部リソースのためのフォーム構築の幾つかのケースについて
  • 複雑なフォームの構築方法について

このガイドは、利用可能なヘルパーとその引数の完全なドキュメントを目指しているわけではありません。 完全なリファレンスが必要であれば、Rails APIドキュメントを参照してください。

1. 基本的なフォームの処理

最も基本的なフォームヘルパーはform_tagです。

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

このように引数無しで呼び出すと、<form>タグが作成され、 submitされると現在のページPOSTされます。 例えば、現在のページが/home/indexだとすると、 生成される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の内容…
</form>

ご覧のように、HTMLに余分に追加されたもの(DIV要素と2つのhiddenのinput要素)が含まれています。 このDIVは、フォームはこれ無しではsubmitを成功させることが出来ないため重要です。 1つ目のnameがutf8のinput要素は、ブラウザが適切にアプリケーションの文字エンコーディングを尊重することを強制します。 これは、アクションが"GET"であれ"POST"であれ作成されます。 2つ目のnameがauthenticity_tokenのinput要素は、クロスサイト・リクエスト・フォージェリの防御と呼ばれるRailsのセキュリティ機能です。 詳細はセキュリティガイドを参照してください。

このガイドでは、このhiddenのinput要素を含むDIVを、簡略化のためにサンプルのコードからは除外しています。

1.1 一般的な検索フォーム

あなたがご存知の多くの基本的なWebのフォームの1つに、検索フォームがあります。 下記のフォームには次の項目が含まれます。

  • "GET"メソッドによるフォーム要素であり、
  • input用のラベルがあり、
  • テキストのinput要素があり、
  • そしてsubmit要素があります。

このフォームを作成するには、form_taglabel_tagtext_field_tag、 そしてsubmit_tagをそれぞれ使用し、次のようになります。

<%= form_tag("/search", method: "get") do %>
  <%= label_tag(:q, "Search for:") %>
  <%= text_field_tag(:q) %>
  <%= submit_tag("Search") %>
<% end %>

これは、下記のHTMLを生成します。

<form accept-charset="UTF-8" action="/search" method="get">
  <label for="q">Search for:</label>
  <input id="q" name="q" type="text" />
  <input name="commit" type="submit" value="Search" />
</form>

各formのinput要素のために、nameからid属性が生成されます。("q"はその例です。) これらのIDはCSSのスタイル、またはJavascriptによるフォームのコントロール制御に役立ちます。

text_field_tagsubmit_tagに加え、HTMLのフォームで使用される要素用の同様のヘルパーが存在します。

検索フォームでは、常に"GET"メソッドを使用します。 こうすることで、特定の検索へのブックマークと、戻る処理を可能にします。 通常多くのケースでRailsは、アクションに正しいHTTP動詞を使用することを奨励しています。

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

form_tagヘルパーは、アクションへのパスとオプションのハッシュの2つの引数を受け取ります。 このハッシュにはフォームのsubmitのmethodと、フォーム要素のclassのようなHTMLオプションを指定します。

link_toヘルパーと同じで、パス引数は文字列にする必要はありません。 これはRailsのルーティングの仕組みによって認識される、URLパラメータのハッシュにすることが出来ます。 ただし、form_tagへの引数が両方ともハッシュになるため、 両方のハッシュを簡略化してしまうと問題が発生します。 例えば、下記のように書いたとします。

form_tag(controller: "people", action: "search", method: "get", class: "nifty_form")
# => '<form accept-charset="UTF-8" action="/people/search?method=get&class=nifty_form" method="post">'

ご覧のとおり、methodclassが生成されるURLのクエリー文字列に追加されます。 これは2つのハッシュを書いたつもりが、実際には1つしか指定されていない事が原因です。 そのため、中括弧を使用してRubyに対して1つ目(または両方)の区切りを伝える必要があります。 次のようにすることで、意図するHTMLを生成することが出来ます。

form_tag({controller: "people", action: "search"}, method: "get", class: "nifty_form")
# => '<form accept-charset="UTF-8" action="/people/search" method="get" class="nifty_form">'

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

Railsは、チェックボックス、テキストフィールド、ラジボタンのようなフォーム要素生成のヘルパーを提供します。 名前の末尾に"_tag"が付く基本的なヘルパーは(text_field_tagとcheck_box_tagのような)、 単一の<input>要素のみを生成します。 これらの1つ目の引数は、常にinputのnameになります。 フォームがsubmitされると、このnameがフォームデータと共に渡され、 コントローラー内にユーザーがフォームから入力した値を持つparamsハッシュが作成されます。 例えば、もしフォームが\u003C%= text_field_tag(:query) %\u003Eを含む場合、 コントローラー内でparams[:query]を使用して、このフィールドの値を取得することが出来ます。

inputに名前を付ける際にRailsは一定の規則に従って、 配列やハッシュのようなスカラ値ではない値のsubmitが出来るようにし、 またそれはparams内でもアクセス可能です。 詳細については、このガイドの7章を参照してください。 これらのヘルパーの詳細な使用方法については、APIドキュメントを参照してください。

1.3.1 チェックボックス

チェックボックスは、有効または無効の設定をユーザーに与えるフォーム要素です。

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

これは、下記を生成します。

<input id="pet_dog" name="pet_dog" type="checkbox" value="1" />
<label for="pet_dog">I own a dog</label>
<input id="pet_cat" name="pet_cat" type="checkbox" value="1" />
<label for="pet_cat">I own a cat</label>

check_box_tagへの1つ目の引数は、もちろんinputのnameです。 2つ目の引数は、当然inputの値です。 この値はチェックボックスのチェックがされると、フォームデータに含まれる(そしてparamsに渡されます)ことになります。

1.3.2 ラジオボタン

ラジオボタンはチェックボックスと似ていて、 排他的なオプションの設定の指定をユーザーに与えます。 (例: ユーザーは1つだけしか選択できません。)

<%= radio_button_tag(:age, "child") %>
<%= label_tag(:age_child, "I am younger than 21") %>
<%= radio_button_tag(:age, "adult") %>
<%= label_tag(:age_adult, "I'm over 21") %>

これは、下記のように出力されます。

<input id="age_child" name="age" type="radio" value="child" />
<label for="age_child">I am younger than 21</label>
<input id="age_adult" name="age" type="radio" value="adult" />
<label for="age_adult">I'm over 21</label>

check_box_tagと同様に、2つ目の引数はradio_button_tagのinputの値になります。 これらの2つのラジオボタンは同じname(age)を共有するため、ユーザーはどちらかの片方のみを選択することになり、 params[:age]には"child"または"adult"のどちらかが格納されます。

常にラベルはチェックボックスとラジオボタンのために使用します。 これらは特定のオプションを指定することでテキストを関連付け、クリック可能な部分を広くし、 ユーザーがinputのクリックを行い易くする効果があります。

1.4 その他のヘルパー

その他の利用されるフォーム要素には、textarea、password、hidden、search、telephone、date、time、color datetime、datetime-local、month、week、URL、emailがあります。

<%= 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) %u003E
<%= datetime_field(:user, :meeting_time) %>
<%= 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) %>

これは、下記のように出力されます。

<textarea id="message" name="message" cols="24" rows="6">Hi, nice site</textarea>
<input id="password" name="password" type="password" />
<input id="parent_id" name="parent_id" type="hidden" value="5" />
<input id="user_name" name="user[name]" type="search" />
<input id="user_phone" name="user[phone]" type="tel" />
<input id="user_born_on" name="user[born_on]" type="date" />
<input id="user_meeting_time" name="user[meeting_time]" type="datetime" />
<input id="user_graduation_day" name="user[graduation_day]" type="datetime-local" />
<input id="user_birthday_month" name="user[birthday_month]" type="month" />
<input id="user_birthday_week" name="user[birthday_week]" type="week" />
<input id="user_homepage" name="user[homepage]" type="url" />
<input id="user_address" name="user[address]" type="email" />
<input id="user_favorite_color" name="user[favorite_color]" type="color" value="#000000" />
<input id="task_started_at" name="task[started_at]" type="time" />

hiddenのinput要素はユーザーには見えませんが、その代わりにテキスト系のinputのようにデータを保持します。 これらの値はJavaScriptで変更可能です。

search、telephone、date、time、color、datetime、datetime-local、month、week、URL、emailは、HTML5のinput要素です。 もし、あなたのアプリケーションが古いブラウザに対応する必要がある場合、 HTML5のpolyfillが必要になります。(CSS(と/または)JavaScriptによって提供されます) このための解決方法には事欠きませんが、 今現在2つのポピュラーなツールに、 Modernizrと、 yepnopeがあり、 HTML5で実装された機能を元にして機能を追加するシンプルな手段を提供してくれます。

もし、passwordのinputフィールドを使用する場合(何らかの用途で)、 あなたはこれらのパラメーターがログに残らないようにアプリケーションを設計した方が良いかもしれません。 これについては、セキュリティガイドを参照してください。

2. モデルオブジェクトの処理

2.1 モデルオブジェクトのヘルパー

フォームでの共通するタスクに、モデルオブジェクトの編集と作成があります。 一方で*_tagヘルパーは確実にこのタスクで使用することが可能で、 これを正しいパラメーター名を使用し、inputに適したデフォルトの値の設定を各タグにするには少々冗長です。 Railsはこのタスクに適したヘルパーを提供してくれます。 これらのヘルパーには、_tag接尾辞がありません。 例えば、text_fieldtext_areaとなります。

これらのヘルパーには、1つ目の引数はインスタンス変数の名前、 2つ目の引数はそのオブジェクト上で呼び出すメソッドの名前(通常は属性)を指定します。 Railsはオブジェクトのためにメソッドの値を返すinput要素の値を設定し、 適切なinput名を設定します。 もし、コントローラーが@personを持ち、そのpersonのnameがHenryでフォームに下記のように含まれれば、

<%= text_field(:person, :name) %>

これは次のように出力されます。

<input id="person_name" name="person[name]" type="text" value="Henry"/>

フォームの送信時にユーザーによって入力された値は、params[:person][:name]に格納されます。 params[:person]ハッシュはPerson.newへ、 または@personがPersonのインスタンスであれば、@person.updateへ渡すのに適したものとなっています。 属性のnameはこれらのヘルパーのための最も一般的な2つ目の引数ですが、これは強制されるものではありません。 上記の例では、personオブジェクトがnamename=メソッドを持ってさえいれば、 問題はありません。

インスタンス変数の名前を渡さなければいけません。 例: :personまたは"person"は、 モデルオブジェクトのインスタンスではありません。

Railsはモデルオブジェクトに関連した検証エラーを表示するヘルパーを提供します。 詳細については、Activeレコードの検証 のガイドを参照してください。

2.2 オブジェクトへのフォームの紐付け

これは快適さを向上するためのものですが、完璧には程遠い状態です。 もしPersonが編集するための属性を多く持つ場合、何回も編集オブジェクトの名前を繰り返し書く事になります。 我々は何とかしてフォームをモデルオブジェクトに紐付けたいと考え、form_forを作りました。

ここで、記事を取り扱うapp/controllers/articles_controller.rbを持つものとします。

def new
  @article = Article.new
end

これは、form_forを使用してapp/views/articles/new.html.erbに、 次のように対応しています。

u003C%= form_for @article, url: {action: "create"}, html: {class: "nifty_form"} do |f| %u003E
  u003C%= f.text_field :title %u003E
  u003C%= f.text_area :body, size: "60x12" %u003E
  u003C%= f.submit "Create" %u003E
u003C% end %u003E

ここで、気をつける必要のある項目が幾つか存在します。

  • @articleは編集される実際のオブジェクトです。
  • 単一のオプションのハッシュが存在します。 ルーティングオプションは:urlハッシュで渡され、 HTMLオプションは:htmlハッシュで渡されます。 また、from要素のid属性を一意のものとするために、:namespaceオプションを指定することも可能です。 このnamespace属性は、生成されたHTMLのidにアンダースコア付きで接頭辞が付けられます。
  • form_forメソッドは、フォームビルダーオブジェクト(f変数)をyieldします。
  • フォーム(を制御する)要素を生成するメソッドは、フォームビルダーオブジェクトf上で呼び出されます。

出力されるHTMLは下記のようになります。

<form accept-charset="UTF-8" action="/articles/create" method="post" class="nifty_form">
  <input id="article_title" name="article[title]" type="text" />
  <textarea id="article_body" name="article[body]" cols="60" rows="12"></textarea>
  <input name="commit" type="submit" value="Create" />
</form>

form_for渡された名前は、フォームの値にアクセスするためのparamsのキーとして使用されます。 ここでの名前はarticleのため、全てのinputはフォームの名前article[attribute_name]を持ちます。 したがって、createアクション内のparams[:article]は、 :title:bodyを持つハッシュになります。 inputの名前についての重要事項については、parameter_namesセクションで確認することが出来ます。

フォームビルダー上で呼び出されるヘルパーメソッドは、 フォームビルダーによって既に管理されているため、編集されるオブジェクトを指定する必要が無いことを除いて、 モデルオブジェクトのヘルパーと同一のものです。

fields_forヘルパーを使用して、実際に<form>タグを作成すること無く同様の紐付けを作成することが可能です。 これは同じフォーム上で編集するモデルオブジェクトを追加する場合に便利です。 例えば、ContactDetailモデルに関連付くPersonモデルを持っている場合、 両方を作成するためのフォームを下記のようにして作成することが出来ます。

u003C%= form_for @person, url: {action: "create"} do |person_form| %u003E
  u003C%= person_form.text_field :name %u003E
  u003C%= fields_for @person.contact_detail do |contact_details_form| %u003E
    u003C%= contact_details_form.text_field :phone_number %u003E
  u003C% end %u003E
u003C% end %u003E

これは下記のように出力されます。

<form accept-charset="UTF-8" action="/people/create" class="new_person" id="new_person" method="post">
  <input id="person_name" name="person[name]" type="text" />
  <input id="contact_detail_phone_number" name="contact_detail[phone_number]" type="text" />
</form>

fields_forによって生み出されるオブジェクトは、 form_forによって生み出されるようなフォームビルダーです。 (事実、form_forは内部でfields_forを呼び出しています。)

2.3 レコード識別への依存

Articleモデルは、アプリケーションユーザーが、直接利用出来るものとします。 そのため、(下記はRails開発でのベストプラクティスであり)resourcesを宣言すべきです。

resources :articles

resourceの宣言には、いくつかの副作用が含まれます。 resourcesの詳細については、Railsのルーティングを参照してください。

RESTfulなresourcesを扱っている場合、もしレコード識別に依存してしまうのであれば、 form_forの呼び出しは非常に簡単になります。 要約すると、モデルインスタンスを渡すだけで、Railsはモデル名とそのRESTを理解してくれます。

## 新しいArticleの作成
# ロングスタイル:
form_for(@article, url: articles_path)

# ショートスタイル (レコード識別が使用されます):
form_for(@article)



## 既存のArticleを編集
# ロングスタイル:
form_for(@article, url: article_path(@article), html: {method: "patch"})

# ショートスタイル:
form_for(@article)

ショートスタイルのform_forは、レコードの新規作成・編集に関係なく、 何故都合良くロングスタイルと同様の事が行えるのかと疑問に思ったかもしれません。 レコード識別は、record.new_record?で問い合わせることで、 レコードが新規作成か否かを認識出来る程度に利口に作られています。 また、正しいsubmit先のパスと、オブジェクトのクラスに基づく正しい名前を選択します。

Railsはまた、自動的にフォームに適したclassidを設定し、 Articleを作成するフォームは、new_articleclassidを持ちます。 もし、idが23のArticleを編集している場合は、 classにはedit_articleが、idにはedit_article_23が設定されます。 これらの属性は、このガイドのREST内では簡略化のため省略させていただきます。

モデルにSTI(単一テーブル継承)を使用する場合、もしサブクラスの親クラスだけがresourcesに宣言されている場合は、 サブクラス上でレコード識別に依存することは出来ません。 モデル名、:url:methodを明示的に指定しなければなりません。

2.3.1 名前空間の扱い

もし名前空間が作られたルートを持つ場合、form_forはこれについても気の利いた略記を用意してくれています。 もし、アプリケーションがadmin名前空間を持つのであれば、

form_for [:admin, @article]

上記のように指定すると、admin名前空間内のarticlesコントローラーへsubmitするフォームを作成します。 (このケースの更新時は、admin_article_path(@article)へのsubmitになります。) もし複数階層の名前空間であっても、文法は同じようなものになります。

form_for [:admin, :management, @article]

Railsのルーティングの仕組みと関連付けの慣習の詳細については、 Railsのルーティングのガイドを参照してください。

2.4 どのようにしてフォームはPATCH、PUT、DELETEメソッドを動作させるのか

RailsフレームワークはアプリケーションをRESTfulな設計にすることを推奨しており、 これはあなたが多くの"PATCH"と"DELETE"リクエスト("GET"と"POST"に加えて)を作ることになることを意味します。 ただし、多くのブラウザはフォームsubmit時に、"GET"と"POST"以外のメソッドをサポートしません。

Railsは"_method"と名付けられたhiddenのinputを使用して、 POST越しに他のメソッドをエミュレートすることでこの問題を回避します。

form_tag(search_path, method: "patch")

これは下記を出力します。

<form accept-charset="UTF-8" action="/search" method="post">
  <div style="margin:0;padding:0">
    <input name="_method" type="hidden" value="patch" />
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
  </div>
  ...

POSTされたデータが解析されると、Railsは特別な_methodパラメーターを考慮し、 HTTPメソッドがその内部で指定されたものであるとして振る舞います。(この例では、"PATCH")

3. 簡単なセレクトボックス作成

HTMLのセレクトボックスは、多量のの特別なマークアップ(選択肢のための各オプションのためのOPTION要素)を必要とするため、 それらを動的に生成してしまうのが非常に有用になります。

マークアップは次のようになります。

<select name="city_id" id="city_id">
  <option value="1">Lisbon</option>
  <option value="2">Madrid</option>
  ...
  <option value="12">Berlin</option>
</select>

これはユーザーに都市名を提供するための都市リストになります。 アプリケーションが内部的に必要なのはそれを取り扱うためのIDだけであるため、それらがoptionの属性値として使用されます。 Railsがどのようにしてこの手助けをしてくれるかを見て行きましょう。

3.1 SelectとOptionタグ

最も包括的なヘルパーはselect_tag(名前が示すように)で、 シンプルにSELECTタグを生成します。

u003C%= select_tag(:city_id, '<option value="1">Lisbon</option>...') %u003E

まずこれから始めていきますが、オプションタグを動的に生成しません。 options_for_selectヘルパーでoptionタグを生成することが可能です。

u003C%= options_for_select([['Lisbon', 1], ['Madrid', 2], ...]) %u003E

出力:

<option value="1">Lisbon</option>
<option value="2">Madrid</option>
...

options_for_selectへの1つ目の引数は入れ子の配列で、 各要素は2つの要素、optionのテキスト(都市(city)名)とoption値(都市(city)ID)を持ちます。 optionの値は、コントローラーへsubmitされるものです。 よく、これはデータベースオブジェクトに対応するidとなりますが、 これを使用する場合はそうすべきではありません。

select_tagoptions_for_selectを繋げて、目的を達成出来ることがお分かりいただけると思います。 マークアップは次のようになります。

<%= select_tag(:city_id, options_for_select(...)) %>

options_for_selectは、その値を渡す事で予め選択するオプションを指定する事が可能です。

<%= options_for_select([['Lisbon', 1], ['Madrid', 2], ...], 2) %>

output:

<option value="1">Lisbon</option>
<option value="2" selected="selected">Madrid</option>
...

Railsはこの値で生成されたoption内の値を見つける度に、selected属性をそのoptionに追加します。

options_for_selectへの2つ目の引数は、目的の値と正確に等価である値にすべきです。 特に、もし値がintegerの2の場合、options_for_selectへ"2"を渡すことは出来ず、2が渡されるべきです。 pramsハッシュから抜き出される値は全て文字列である事を把握しておいてください。

:include_blankまたは:promptが提供されない場合、 もしselectのrequired属性がtrue、sizeが1、multipleがtrueで無ければ、 :include_blankはtrueに強制されます。

ハッシュを使用して、任意の属性をoptionに追加することが可能です。

u003C%= options_for_select([['Lisbon', 1, {'data-size' => '2.8 million'}], ['Madrid', 2, {'data-size' => '3.2 million'}]], 2) %u003E

出力:

<option value="1" data-size="2.8 million">Lisbon</option>
<option value="2" selected="selected" data-size="3.2 million">Madrid</option>
...

3.2 モデルを扱うセレクトボックス

フォームの要素を特定のデータベースのモデルに結び付けたいというケースが多く、 その期待に応えるようにRailsはそのためのヘルパーを提供します。 他のフォームヘルパーと一貫して、モデルを扱う場合は、_tag接尾辞をselect_tagから取り除きます。

# controller:
@person = Person.new(city_id: 2)
# view:
u003C%= select(:person, :city_id, [['Lisbon', 1], ['Madrid', 2], ...]) %u003E

3つ目の引数であるoptionの配列は、options_for_selectに渡すものと同じ類のものであることに���意してください。 これの1つの利点として、もしユーザーが既に何かを選択されている場合、現在選択されている都市について考慮する必要が無いことが挙げられます。 Railsは@person.city_id属性から読み取ることで、これを行ってくれます。

他のヘルパーと使用するとして、もしselectヘルパーを@personオブジェクトの範囲内でのフォームビルダー上で使用する場合、 文法は次のようになります。

# select on a form builder
u003C%= f.select(:city_id, ...) %u003E

もしselect(または、collection_selectselect_tagのようなヘルパーも同様に)を使用して、 belongs_toの関連付けをセットしたい場合、関連付けされるもの自身の名前では無く、外部キー(この例ではcity_id)を渡す必要があります。 Person.newまたはupdateparamsハッシュを渡す際に、 もし、city_idの代わりにcityを指定すると、 ActiveRecord::AssociationTypeMismatch: City(#17815740) expected, got String(#1138750)のようなエラーが発生します。 別の見方をすると、フォームヘルパーは属性のみを編集しているという事が分かります。 また、ユーザーによる外部キーの直接編集を許可することによる、潜在的なセキュリティへの影響も考慮しておく必要があります。

3.3 任意のオブジェクトからのoptionタグの生成

options_for_selectを使用して、optionタグを生成するには、 各オプションのテキストと値を含む配列を作成する必要があります。 ただし、もしCityモデルを持っているのであれば(おそらくActive Recordの1つとして)、 それらのオブジェクトのコレクションからoptionタグを生成したいと考えるのではないでしょうか? 1つの解決策として、それらを繰り返し処理することで入れ子の配列を作成するというものがあります。

u003C% cities_array = City.all.map { |city| [city.name, city.id] } %u003E
u003C%= options_for_select(cities_array) %u003E

これは完璧で正当な解決策ですが、Railsは冗長性をより減らすために、 options_from_collection_for_selectを提供します。 このヘルパーは、任意のオブジェクトのコレクションと、 optionの値を読み取るメソッド名、optionのテキストを読み取るメソッド名をそれぞれ受け取ります。

u003C%= options_from_collection_for_select(City.all, :id, :name) %u003E

名前から分かるように、これはoptionタグだけを生成します。 動作するセレクトボックスを生成するには、options_for_selectでそうしたように、 これをselect_tagと織り交ぜて使用する必要があります。 モデルのオブジェクトと一緒に動作させる場合は、 selectselect_tagoptions_for_selectを兼ねたように、 collection_selectselect_tagoptions_from_collection_for_selectを兼ねます。

u003C%= collection_select(:person, :city_id, City.all, :id, :name) %u003E

collection_selectへのoptions_from_collection_for_selectは、 selectへのoptions_for_selectに該当します。

options_for_selectに渡されるペアは、1つ目がnameで2つ目をidとすべきですが、 options_from_collection_for_selectでは、1つ目がvalueのメソッドで2つ目がtextメソッドになります。

3.4 タイムゾーンと地域選択

Rails内でタイムゾーンをサポートするためには、ユーザーに対して彼らのタイムゾーンが何かを尋ねる必要があります。 それをするためにcollection_selectを使用して、予め定義されているTimeZoneオブジェクトのリストから、 selectのoptionを生成する必要がありますが、単にこれを含むtime_zone_selectを使用することが可能です。

<%= time_zone_select(:person, :time_zone) %>

また、より手動的(それ故、よりカスタマイズしやすい)に同じことを行うtime_zone_options_for_selectヘルパーも存在します。 これら2つのメソッドで使用可能な引数については、APIドキュメントを参照してください。

Railsは国を選択するcountry_selectを持っていましたが、 これはcountry_selectプラグインに巻き取られました。 これを使用する際には、リストに含まれる名前、含まれない名前について、 物議を呼ぶことになるかもしれないということを把握しておいてください。 (また、これがRailsから外された理由でもあります。)

4. 日付と時間フォームヘルパーの使用

HTML5による日付・時間要素を生成するフォームヘルパーを使用しないで、 代わりの日付・時間ヘルパーを使用する事を選択することが可能です。 これらの日付と時間ヘルパーは、他の全てのフォームヘルパーと異なり、配慮しなければいけない2つの重要な点があります。

  • 日付と時間は、単一のinput要素では表現されません。 代わりにコンポーネント毎に複数持つようになるため(年、月、日、他)、日付・時間はparamsのハッシュ内で単一ではありません。
  • 他のヘルパーは、ヘルパーが骨組みだけなのか、モデルオブジェクト上で操作されるのかを指し示すために、 _tag接尾辞を使用します。 日付と時間では、select_dateselect_timeselect_datetimeが骨組みだけのヘルパーで、 date_selecttime_selectdatetime_selectはモデルオブジェクトのヘルパーに相当します。

これらの種類のヘルパーは両方とも、異なるコンポーネント(年、月、日、他)の一連のセレクトボックスを生成します。

4.1 骨組みだけのヘルパー

select_*の類のヘルパーは、現在選択されている値として使用されるDate、Time、 またはDateTimeのインスタンスを第1引数として取得します。 このパラメーターを省略して、現在の日時を使用することも出来ます。例えば、

u003C%= select_date Date.today, prefix: :start_date %u003E

出力は下記のようになります。(簡潔にするために、実際のoptionのvalueを省略しています。)

<select id="start_date_year" name="start_date[year]"> ... </select>
<select id="start_date_month" name="start_date[month]"> ... </select>
<select id="start_date_day" name="start_date[day]"> ... </select>

上記のinputは、最終的に:year:month:dayを持つ、 params[:start_date]ハッシュになります。 実際のTimeまたはDateオブジェクトを取得するために、これらの値を抜き出して、適切なコンストラクタに渡す必要があります。 下記はその一例になります。

Date.civil(params[:start_date][:year].to_i, params[:start_date][:month].to_i, params[:start_date][:day].to_i)

:prefixオプションは、paramsハッシュから日付けコンポーネントのハッシュを取得する際に使用されます。 ここでは、start_dateが設定されており、もし省略されるとデフォルトのdateになります。

4.2 モデルオブジェクトヘルパー

select_dateは、Activeレコードが期待する1つの属性に対してのparamsハッシュの各要素として、 Activeレコードオブジェクトを更新または作成するフォームとしては正しく動作しません。 日付・時間モデルオブジェクトのヘルパーは特別な名前を使用してパラメーターを送信します。 Activeレコードがそれらの名前を参照する際は、他のパラメーターを連結し、組み立てのため適切なカラム型を与えなければいけません。 例えば、

<%= date_select :person, :birth_date %>

出力は下記のようになります。(簡潔にするために、実際のoptionのvalueを省略しています。)

<select id="person_birth_date_1i" name="person[birth_date(1i)]"> ... </select>
<select id="person_birth_date_2i" name="person[birth_date(2i)]"> ... </select>
<select id="person_birth_date_3i" name="person[birth_date(3i)]"> ... </select>

pramsは下記のようなハッシュになります。

{:person => {'birth_date(1i)' => '2008', 'birth_date(2i)' => '11', 'birth_date(3i)' => '22'}}

これがPerson.new(またはupdate)に渡される際に、 Activeレコードはこれらのパラメーターは全てbirth_date属性の組み立てに使用されるべきであることを発見し、 Date.civilのような機能に渡すべき順番を識別するために接尾辞を使用します。

4.3 共通のオプション

どちらのタイプのヘルパーも、個別のセレクトタグを生成するための機能のコアな設定を使用するため、 両方とも多くの同じオプションを受け取ります。 特にデフォルトでは、Railsは現在の年から前後5年のyearのオプションを生成します。 もしこれが適切な範囲で無いのであれば、:start_year:end_yearを使用してこれを上書きします。 利用可能な完全なオプションのリストについては、APIドキュメントを参照してください。

モデルオブジェクトを使用した動作にはdate_selectを使用し、 日時による結果のフィルタリングを行う検索フォームのような、 その他のケースではselect_dateを使用すべきです。

組み込みの日付ピッカーは、日付けと週の日の関係性を調べる事が、多くのケースでユーザーにとって扱いづらいものになっています。

4.4 個別のコンポーネント

時に年または月のような、単一日付コンポーネントの表示を必要とするケースがあるかもしれません。 Railsはこれをするためのヘルパーを、それぞれselect_yearselect_monthselect_dayselect_hourselect_minuteselect_secondとして提供します。 これらのヘルパーは、とても簡単なものです。 デフォルトでこれらは、後ろに日時コンポーネントの名前が付いたinputフィールドを生成し、 (例えば、"year"ならselect_year、"month"ならselect_month等です。) また:field_nameオプションを使用することで、上書きすることが可能です。 :prefixオプションは、select_dateselect_timeと同じように動作し、 同じデフォルト値を持ちます。

1つ目のパラメーターは選択するべき値を指定し、Date、Time、DateTimeのいずれかのインスタンスにすることが可能で、 その場合は該当するコンポーネントが抽出されるか、数値になるはずです。 下記はその例になります。

<%= select_year(2009) %>
<%= select_year(Time.now) %>

仮に現在2009年だとすれば、これは同じ出力が生成され、 params[:date][:year]によって、ユーザーが選択した値を取得することが出来ます。

5. アップロードファイル

人物の写真であれ、処理をするためのデータを含むCSVファイルであれ、 どのような種類のファイルであってもアップロードで行われる処理は共通のものになります。 ファイルアップロードにおいて覚えておいてもらいたい最も重要な事は、 出力するフォームのエンコーディングを"multipart/form-data"にしなければいけないという事です。 もし、form_forを使用しているのであれば、これはそれを自動的に行なってくれます。 もし、form_tagを使用しているのであれば、 下記の例についても、それぞれ自分でこの設定を行わなければいけません。

下記のどちらのフォームも、ファイルをアップロードします。

<%= form_tag({action: :upload}, multipart: true) do %>
  <%= file_field_tag 'picture' %>
<% end %>

<%= form_for @person do |f| %>
  <%= f.file_field :picture %>
<% end %>

Railsはこれまでと同様に、骨組みだけを提供するfile_field_tagと、 モデルに関連付けられるfile_fieldのヘルパーのペアを提供します。 他のヘルパーとの違いは、fileのinputにはそれをする手段が無いとして、 デフォルトの値を設定する事が出来ない事だけです。 予想がついているかもしれませんが、1つ目のアップロードファイルはparams[:picture]になり、 2つ目はparams[:person][:picture]になります。

5.1 何をアップロードするか

paramsハッシュ内のオブジェクトは、IOのサブクラスのインスタンスです。 アップロードファイルのサイズによって、これは実際のStringIOになるかもしれないし、 一時ファイルによるファイルのインスタンスになるかもしれません。 どちらのケースのオブジェクトも、ユーザーのコンピューター上で持つファイルの名前を含むoriginal_filename属性と、 アップロードファイルのMIME typeが含まれるcontent_type属性を持ちます。 下記のスニペットは、元のファイルを同じファイル名で#{Rails.root}/public/uploads下にアップロードコンテンツを保存します。 (フォームは前述の例ものものとします。)

def upload
  uploaded_io = params[:person][:picture]
  File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'wb') do |file|
    file.write(uploaded_io.read)
  end
end

ファイルがアップロードされる度、ファイルの格納場所(ディスク上、Amazon S3上、その他)への配置、 リサイズした画像ファイルのモデルへの関連付け、サムネイルの生成など、多くの潜在的な処理が発生しています。 これらの込み入った処理は、このガイドの範疇を超えるてしまいますが、 こういった処理を手助けするために設計されたライブラリが幾つか存在します。 よく知られているものに、 CarrierWaveと、 Paperclipがあります。

もしユーザーがファイルを選択しなかった場合、対応するパラメーターには空文字列が入ります。

5.2 Ajaxによる取り扱い

他のフォームの非同期と異なり、ファイルアップロードのフォームはremote: trueを使用したform_forのように単純ではありません。 Ajaxフォームによるシリアライズ化は、ブラウザ内部のJavaScriptの実行によって行われますが、 JavaScriptはハードドライブからファイルを読み込むことは出来ないため、ファイルをアップロードすることが出来ません。 一般的にこういったケースでは、この問題を回避するためにユーザーにとって視認出来ないようなiframeを使用しておき、 そのiframeに対してsubmit処理を行います。

6. フォームビルダーのカスタマイズ

これまでに言及してきた、form_forfields_forによって生成されたオブジェクトが、 FormBuilder(または、そのサブクラス)のインスタンスになります。 フォームビルダーは単一のオブジェクトのため、フォーム要素の表示の概念をカプセル化します。 通常の方法としてフォームのためにヘルパーを書くことが出来る一方、 FormBuilderのサブクラスにし、そこにヘルパーを追加することも可能です。 例えば、

<%= form_for @person do |f| %>
  <%= text_field_with_label f, :first_name %>
<% end %>

これを、次のように書き換えることが可能です。

<%= form_for @person, builder: LabellingFormBuilder do |f| %>
  <%= f.text_field :first_name %>
<% end %>

これは、次のようなLabellingFormBuilderクラスを定義することで実現します。

class LabellingFormBuilder < ActionView::Helpers::FormBuilder
  def text_field(attribute, options={})
    label(attribute) + super
  end
end

もし、これを頻繁に使用するのであれば、builder: LabellingFormBuilderオプションに自動的に適用する labeled_form_forヘルパーを定義することが可能です。(翻訳に自信なし)

また、フォームビルダーは下記のようにされた際に、何を行うかを決定するのにも使用されます。

<%= render partial: f %>

もし、fがFormBuilderのインスタンスであれば、フォームビルダーに設定されている部分的なオブジェクトが、 フォームを部分的(partial)に描画します。(翻訳に自信なし) もし、フォームビルダーがLabellingFormBuilderクラスのものであれば、 labelling_formが代わりに部分的に描画されます。(翻訳に自信なし)

7. 名付規約パラメータの理解

これまでのセクションで見てきたようにフォームからの値は、 paramsのトップ階層にも、その他のハッシュの入れ子にもすることが可能です。 例えば、標準的なPersonモデルへのcreateアクションにおいて、 params[:person]は通常はPersonを作成するための全ての属性を含むハッシュになります。 このparamsハッシュは、配列、ハッシュの配列を同じように含めることも可能です。

基本的にHTMLフォームはデータ構成の並び順については把握しておらず、 それらは全て名前-値のペアであり、それはプレーンな文字列のペアです。 アプリケーションで確認出来る配列とハッシュは、Railsが使用するパラメーターの名付けの慣習の結果になります。

このセクションでの内容(パラメーターがどのよなハッシュに変換されるか)を、 直接コンソールからRackのパラメーターのパーサーを実行することで、手早く内容の確認を行うことが可能です。 下記はその一例になります。

Rack::Utils.parse_query "name=fred&phone=0123456789"
# => {"name"=>"fred", "phone"=>"0123456789"}

7.1 基本的な構造

2つの基本的な構造に、配列とハッシュがあります。 params内の値のアクセスのために、 ハッシュは文法に反映します。 例えば、フォームに下記のように含まれるとすると、

<input id="person_name" name="person[name]" type="text" value="Henry"/>

paramsのハッシュは次のようになり、

{'person' => {'name' => 'Henry'}}

params[:person][:name]で、コントローラー内にsubmitされた値を取得します。

ハッシュは必要に応じて、何層にも入れ子にすることが可能です。 例えば、

<input id="person_address_city" name="person[address][city]" type="text" value="New York"/>

このparamsハッシュは下記の結果になります。

{'person' => {'address' => {'city' => 'New York'}}}

通常、Railsは重複したパラメーター名を無視しますが、 もしパラメーター名が角括弧[]に空文字が設定されたものを含む場合、それらは配列として蓄積されます。 もしユーザーが複数の電話番号を入力出来るようにしたい場合、下記のようにフォーム内に配置します。

<input name="person[phone_number][]" type="text"/>
<input name="person[phone_number][]" type="text"/>
<input name="person[phone_number][]" type="text"/>

このparams[:person][:phone_number]は、配列になります。

7.2 結合

これら配列とハッシュを混合し、調和させる事が可能です。 例えば、前述した例ではハッシュの1要素を配列にしても、ハッシュの配列でも、どちらでも構いません。 例えば、アドレスの番号のフォームを下記のようなフォーム部品を繰り返すことで作成しても構いません。

<input name="addresses[][line1]" type="text"/>
<input name="addresses[][line2]" type="text"/>
<input name="addresses[][city]" type="text"/>

このparams[:addresses]の結果は、line1line2cityのキーを持つハッシュの配列になります。 Railsは現在のハッシュに既にinput名が存在していることが判明すると、新しいハッシュとして配列に蓄積していくことを決定します。

制限はありますが、任意にハッシュを入れ子にし、"配列のような"1階層だけのものも許可されます。(翻訳に自信なし) 配列は通常ハッシュに置換することが可能です。 例えば、モデルオブジェクトの配列の代わりに、それらのID、インデックス番号mまたはその他のパラメーターをキーとした、 モデルオブジェクトのハッシュとすることが可能です。

check_boxヘルパーを使用した配列のパラメーターは思うような動作をしてくれません。 HTMLの仕様に従い、チェックの無いチェックボックスは値が送信されませんが、 常に何らかの値を送信してくれた方が都合が良いというケースがよくあります。 check_boxヘルパーは、補助的なhiddenのinputを同じ名前で作成することで、これを擬似的に行います。 もしチェックボックスがチェックされないと、hiddenのinputだけがsubmitされ、 チェックされると両方submitされますが、その場合はチェックボックスの値が優先されます。 配列のパラメーターと一緒に動作させると、重複したinput名は新しい配列要素として開始する際の決定方法になるため、 この重複送信はRailsを混乱させます。 この場合、check_box_tagを使用するか、配列の代わりにハッシュを使用するのが望ましいと言えます。

7.3 フォームヘルパーの使用

ここまでのセクションで、Railsのフォームヘルパーを全く使用していませんでした。 自身でinput名を決めてそれをtext_field_tagのようなヘルパーに直接渡す事が出来る一方、 Railsは高階層のサポートも提供します。 この処理を行うための2つのツールが、form_forへの名前パラメーターと、 ヘルパーが取得するfields_forとその:indexオプションになります。

personの各アドレスのために、編集フィールドが設定されたフォームを描画したいとします。 そのフォームは例えば、次のようになります。

<%= form_for @person do |person_form| %>
  <%= person_form.text_field :name %>
  <% @person.addresses.each do |address| %>
    <%= person_form.fields_for address, index: address.id do |address_form|%>
      <%= address_form.text_field :city %>
    <% end %>
  <% end %>
<% end %>

personが23と45の、2つのアドレスを持つとみなすと、 これは次のような出力を生成します。

<form accept-charset="UTF-8" action="/people/1" class="edit_person" id="edit_person_1" method="post">
  <input id="person_name" name="person[name]" type="text" />
  <input id="person_address_23_city" name="person[address][23][city]" type="text" />
  <input id="person_address_45_city" name="person[address][45][city]" type="text" />
</form>

このparamsハッシュの結果は、次のようになります。

{'person' => {'name' => 'Bob', 'address' => {'23' => {'city' => 'Paris'}, '45' => {'city' => 'London'}}}}

最初のフォームビルダー上でfields_forを呼び出している事から、 Railsはこれらのinputはpersonのハッシュの一部であるべきとういことを認識します。 :indexオプションを指定することによって、inputの名前をperson[address][city]にする代わりに、 addressとcityの間に角括弧[]でインデックスを囲ったものを差し込むことをRailsに伝えます。 これは、変更すべきAddressのレコードを発見し易いため、便利です。 それ以外にも意味のあるもの、文字列、またnilであっても渡すことが可能です(結果として、配列内のパラメーターになります。)。

より入り組んだネストを作成するために、input名の最初の一部分(前述の例であれば、person[address])に明示的に指定する事が可能です。

<%= fields_for 'person[address][primary]', address, index: address do |address_form| %>
  <%= address_form.text_field :city %>
<% end %>

これは下記のように生成されます。

<input id="person_address_primary_1_city" name="person[address][primary][1][city]" type="text" value="bologna" />

input名の最後の一般的なルールとして、fields_for/form_forに渡された名前、 indexの値、属性の名前を連結するというものがあります。 text_fieldのようなヘルパーに直接:indexオプションを渡すことも可能ですが、 大抵はinput要素に個別に行うよりも、フォームビルダー層でこれを指定する方が冗長的な作業を少なくすることが出来ます。

ショートカットとして、[]を名前に追記することで、:indexオプションを省略する事が可能です。 これは、:indexをaddressに指定したのと同じことになります。

<%= fields_for 'person[address][primary][]', address do |address_form| %>
  <%= address_form.text_field :city %>
<% end %>

生成されて出力されるものは、前述の例と同じになります。

8. 外部リソースへのフォーム

もし、何らかのデータを外部リソースにPOSTする必要がある場合であっても、 Railsのフォームヘルパーを使用してフォームを作成することが可能です。 ただし、authenticity_tokenが必要になるケースもありあmす。 form_tagオプションにauthenticity_token: 'your_external_token'パラメーターを渡すことで、 これを行うことが可能です。

<%= form_tag 'http://farfar.away/form', authenticity_token: 'external_token') do %>
  Form contents
<% end %>

決済のような外部リソースにデータをsubmitする際に、外部APIによって制限のあるフォームを使用することがあるかもしれません。 そういったケースでは、あなたはauthenticity_tokenのhiddenフィールドを一切作成したくないと考えるかもしれません。 この場合、:authenticity_tokenオプションにはfalseを渡します。

<%= form_tag 'http://farfar.away/form', authenticity_token: false) do %>
  Form contents
<% end %>

form_forにも同じように利用することが出来ます。

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

また、もしauthenticity_tokenを描画して欲しくないのであれば、

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

9. 複雑なフォームの構築

多くのアプリケーションは、単一のオブジェクトを編集する単純なフォームでは収まりきらないものになります。 例えば、Personを作成する際に、あなたはユーザーに複数のaddressのレコード(自宅、職場、他)を持つ事を許可したい(同じフォーム上で)と考えるかもしれません。 後ほどpersonを編集する際に、ユーザーは必要に応じてアドレスの追加、削除、編集が出来るべきです。

9.1 モデルの設定

Activeレコードはaccepts_nested_attributes_forメソッドを通じて、モデル層のサポートを提供します。

class Person < ActiveRecord::Base
  has_many :addresses
  accepts_nested_attributes_for :addresses
end

class Address < ActiveRecord::Base
  belongs_to :person
end

これは、addresses_attributes=メソッドをPerson上に作成し、 addressの作成、更新、(任意)削除を可能にしてくれます。

9.2 フォームの構築

下記のフォームはユーザーへ、Personとそれに関連づくaddressの生成を可能にしてくれます。

<%= form_for @person do |f| %>
  Addresses:
  <ul>
    <%= f.fields_for :addresses do |addresses_form| %>
      <li>
        <%= addresses_form.label :kind %>
        <%= addresses_form.text_field :kind %>

        <%= addresses_form.label :street %>
        <%= addresses_form.text_field :street %>
        ...
      </li>
    <% end %>
  </ul>
<% end %>

関連付けは入れ子の属性を受け取ると、fields_forは関連付けの要素毎に、そのブロックを描画します。 特に、もしpersonがaddressを持たなければ、何も描画されません。 少なくともユーザーに対して1つのフィールドを表示するために、 コントローラーで空のセットを1つまたは複数buildしておくのが、一般的なパターンです。 下記の例は、新しく作成するpersonフォーム上にaddressの入力フィールドを3セット描画します。

def new
  @person = Person.new
  3.times { @person.addresses.build}
end

fields_foraccepts_nested_attributes_forによって生成されるアクセサーで期待されるフォーマットで、 パラメーターに名前を付けるフォームビルダーを生成します。 例えば、2つのアドレスを持つユーザーを作成する場合、 送信されるパラメーターは次のようになります。

{
    :person => {
        :name => 'John Doe',
        :addresses_attributes => {
            '0' => {
                :kind  => 'Home',
                :street => '221b Baker Street',
            },
            '1' => {
                :kind => 'Office',
                :street => '31 Spooner Street'
            }
        }
    }
}

:addresses_attributesハッシュのキーは重要では無く、 それらは単に各アドレスで異なっている必要があります。

もし関連付けられたオブジェクトが既にsaveされた場合、 fields_forは保存したれコードのIDをhiddenのinputとして自動的に生成します。 これはfields_forinclude_id: falseを渡すことで無効にする事が出来ます。 inputタグが正当なHTMLにならない場所に自動生成されてしまうような場合、 またはORMを使用して子要素がidを持たないような場合に、これを使用したいと考えるかもしれません。(翻訳に自信なし)

9.3 コントローラー

通常、コントローラー内ではパラメーターをモデルに渡す前に、パラメーターのホワイトリストを必要とします。

def create
  @person = Person.new(person_params)
  # ...
end

private
def person_params
  params.require(:person).permit(:name, addresses_attributes: [:id, :kind, :street])
end

9.4 オブジェクトの削除

accepts_nested_attributes_forallow_destroy: trueを渡すことで、 ユーザーに対して関連付けられたオブジェクトを削除する事を許可することが出来ます。

class Person < ActiveRecord::Base
  has_many :addresses
  accepts_nested_attributes_for :addresses, allow_destroy: true
end

もし、オブジェクトの属性のハッシュが、値が'1'または'true'の_destroyキーを含む場合、 オブジェクトは削除されます。 このフォームは、ユーザーに対してアドレスの削除を許可します。

<%= form_for @person do |f| %>
  Addresses:
  <ul>
    <%= f.fields_for :addresses do |addresses_form| %>
      <li>
        <%= check_box :_destroy%>
        <%= addresses_form.label :kind %>
        <%= addresses_form.text_field :kind %>
        ...
      </li>
    <% end %>
  </ul>
<% end %>

コントローラー内のホワイトリストのパラメーター(params)に、_destroyも含める更新も忘れないでください。

def person_params
  params.require(:person).
    permit(:name, addresses_attributes: [:id, :kind, :street, :_destroy])
end

9.5 空レコードの防止

ユーザーに入力されなかったフィールドのセットを無視する事が、有用であるケースがよくあります。 これは、:reject_ifのprocをaccepts_nested_attributes_forに渡すことで制御することが出来ます。 このprocはフォームによって送信された属性の各ハッシュ毎に呼び出されます。 もしprocがfalseを返すと、Activeレコードはそのハッシュの関連付けオブジェクトを生成しません。 下記の例では、kindが設定された場合のみ、addressの生成を試みます。

class Person < ActiveRecord::Base
  has_many :addresses
  accepts_nested_attributes_for :addresses, reject_if: lambda {|attributes| attributes['kind'].blank?}
end

便利な方法として、代わりに:all_blankシンボルを渡すことで、 _destroyを除く全ての属性が空の場合にレコードを除外するprocを生成します。

9.6 オンザフライ(即興・即座)フィールド追加

複数のセットのフィールドを予め描画しておくよりも、ユーザーが'新しい子要素の追加'ボタンを押した場合にのみ、 それらを追加したいと考えるかもしれません。 Railsはこれをサポートするための組み込み機能を提供していません。 新しいフィールドのセットが生成された際に、関連付けられる配列のキーを一意に確定しなければなりません。 これには一般的に、JavaScriptの現在の日時(エポックからのミリ秒)が使用されます。

 Back to top

© 2010 - 2017 STUDIO KINGDOM