Rails2.1でform_forブロックの中のrender :partialの悩み解決!
以前、form_forブロック内の共通する部分を、パーシャルファイル(render :partial)として抜き出すときの書き方で悩んでいたい時期があった。実務的にはどうとでも書けてしまうので、そんなに深く悩む必要も無いのだが、徹底的なDRYを目指すRailsらしい書き方はどんな感じになるか気になっていたのだ*1。最近までずっと...。
で、Ruby on Rails 2.1 の変更点 PDF 日本語訳を読んでいたら、ようやくその答えが見つかったので嬉しくなってしまった。
Rails 2.1のscaffold
- ソフトウェアの名前とダウンロード先を保存する適当なサンプルを作ってみる。
$ cd $ rails partial_test $ cd partial_test $ script/generate scaffold software name:string url:string $ rake db:migrate
- あっという間に動くものは出来上がるので、newとeditファイルを確認すると以下のようになっている。
- これだと、nameとurlのフォームの見栄えを変更しようとした時、同じ修正を2回繰り返す必要がある。(たしかrails2.0以前は、_formファイルに抜き出して、共用していた記憶が...。)
<%# ビュー: app/views/softwares/new.html.erb %> <h1>New software</h1> <% form_for(@software) do |f| %> <%= form.error_messages %> <p> <%= f.label :name %> <%= f.text_field :name %> </p> <p> <%= f.label :url %> <%= f.text_field :url %> </p> <p> <%= f.submit "Create" %> </p> <% end %> <%= link_to 'Back', softwares_path %>
<%# ビュー: app/views/softwares/edit.html.erb %> <h1>Editing software</h1> <% form_for(@software) do |f| %> <%= form.error_messages %> <p> <%= f.label :name %> <%= f.text_field :name %> </p> <p> <%= f.label :url %> <%= f.text_field :url %> </p> <p> <%= f.submit "Update" %> </p> <% end %> <%= link_to 'Show', @software %> | <%= link_to 'Back', softwares_path %>
ブロック内でのrender :partial記法
Rails2.1からform_forブロック内で以下のように書けるようになった。
<%# ビュー: app/views/softwares/new.html.erb %> <h1>New software</h1> <% form_for(@software) do |f| %> <%= render :partial=>f %> <p> <%= f.submit "Create" %> </p> <% end %> <%= link_to 'Back', softwares_path %>
<%# ビュー: app/views/softwares/edit.html.erb %> <h1>Editing software</h1> <% form_for(@software) do |f| %> <%= render :partial=>f %> <p> <%= f.submit "Update" %> </p> <% end %> <%= link_to 'Show', @software %> | <%= link_to 'Back', softwares_path %>
<%# ビュー: app/views/softwares/_form.html.erb %> <%= form.error_messages %> <p> <%= form.label :name %> <%= form.text_field :name %> </p> <p> <%= form.label :url %> <%= form.text_field :url %> </p>
- form_forブロック内でブロック引数を:render :partial=>fのように指定すると...(ブロック引数名はfでも、abcでも、任意の名前でOK)
- _formファイルを呼び出して描画する。(render :partialの引数がブロック引数の場合は_formファイルの描画という規約になっているようだ。)
- _formファイルを描画する時には、ブロック引数の内容が変数formに引き継がれているので、<%= form.text_field :name %>のような書き方が可能になり、同じform_forブロック内のように扱える。
- つまり、ブロック引数がfだとして、以下の書き方は同等なのだ。
<%= render :partial=>f %> 以下と同等 <%= render :partial=>'form', :locals=>{:form=>f} %>
自分がRailsを触り始めた頃からの、一番シンプルな書き方がまた出来るようになって嬉しい!
-
-
- それにしても、もしRails2.1から触り始めたら、この書き方で「うん、なるほど!」とすんなり理解できるのだろうか?(Railsの多少の歴史を知っている今なら納得できるが)自分にとっては超アウンの呼吸的な書き方に見える。おそらく「何で_formファイルが描画されるの?」でまた悩んでしまいそうだ...。
-
*1:Rails2.0.2から、scaffoldでもnewとeditの共通項目を_formとして抜き出さなくなってしまった。なぜ?