フォームヘルパー
Webアプリケーション内のフォームは、ユーザー入力にとって欠かせないインターフェースです。 ただし、フォームのマークアップ構築とメンテナンスは、フォームのコントローラー名とそれらの多すぎる属性のため、 すぐに冗長になりがちです。 Railsはこれらの複雑さを、ビューヘルパーのためのフォームのマークアップ生成を提供することで回避します。 ただし、それらは異なるユースケースを持つため、 これらを使用する前に開発者はこの同じようなヘルパーメソッドについての全ての違いを知っていおく必要があります。
このガイドを読むことで、次の事が学べるはずです。
- アプリケーション内に、検索フォームとそれに類似した一般的なフォームを、特定のモデルを表さずに作成する方法について。
- 特定のデータベースレコードの作成と編集のためのモデルが中心となるフォームの作成方法について。
- 複数タイプのデータから、セレクトボックスの作成方法について
- Railsが提供する日付・時間ヘルパーについて
- ファイルアップロードのフォームの違いについて
- 外部リソースのためのフォーム構築の幾つかのケースについて
- 複雑なフォームの構築方法について
このガイドは、利用可能なヘルパーとその引数の完全なドキュメントを目指しているわけではありません。 完全なリファレンスが必要であれば、Rails APIドキュメントを参照してください。
- 1. 基本的なフォームの処理
- 2. モデルオブジェクトの処理
- 3. 簡単なセレクトボックス作成
- 4. 日付と時間フォームヘルパーの使用
- 5. アップロードファイル
- 6. フォームビルダーのカスタマイズ
- 7. 名付規約パラメータの理解
- 8. 外部リソースへのフォーム
- 9. 複雑なフォームの構築
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="✓" />
<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_tag
、label_tag
、text_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_tag
とsubmit_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">'
ご覧のとおり、method
とclass
が生成される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_field
、text_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オブジェクトがname
とname=
メソッドを持ってさえいれば、
問題はありません。
インスタンス変数の名前を渡さなければいけません。
例: :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はまた、自動的にフォームに適したclass
とid
を設定し、
Articleを作成するフォームは、new_article
のclass
とid
を持ちます。
もし、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="✓" />
<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_tag
とoptions_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_select
、select_tag
のようなヘルパーも同様に)を使用して、
belongs_to
の関連付けをセットしたい場合、関連付けされるもの自身の名前では無く、外部キー(この例ではcity_id
)を渡す必要があります。
Person.new
またはupdate
へparams
ハッシュを渡す際に、
もし、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
と織り交ぜて使用する必要があります。
モデルのオブジェクトと一緒に動作させる場合は、
select
がselect_tag
とoptions_for_select
を兼ねたように、
collection_select
がselect_tag
とoptions_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_date
、select_time
、select_datetime
が骨組みだけのヘルパーで、date_select
、time_select
、datetime_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_year
、select_month
、
select_day
、select_hour
、select_minute
、
select_second
として提供します。
これらのヘルパーは、とても簡単なものです。
デフォルトでこれらは、後ろに日時コンポーネントの名前が付いたinputフィールドを生成し、
(例えば、"year"ならselect_year
、"month"ならselect_month
等です。)
また:field_name
オプションを使用することで、上書きすることが可能です。
:prefix
オプションは、select_date
とselect_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_for
とfields_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]
の結果は、line1
、line2
、
city
のキーを持つハッシュの配列になります。
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_for
はaccepts_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_for
にinclude_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_for
へallow_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の現在の日時(エポックからのミリ秒)が使用されます。
© 2010 - 2017 STUDIO KINGDOM