5.12.パーシャルでビューの重複コードを解消する
前節で作ったedit.html.erbはnew.html.erbとすっごく似てましたね。
記事の更新画面と作成画面なのでそりゃあ似ても仕方ないでしょう。
パーシャル(部分テンプレート)を利用すれば、コードの重複を解消できます。
(「同じことを繰り返すな (Don't Repeat Yourself: DRY)」という哲学もありましたね)
↓似ている二つのビュー
<h1>New Article</h1>
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
<% if @article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@article.errors.count, "error") %> prohibited
this article from being saved:</h2>
<ul>
<% @article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
<%= link_to 'Back', articles_path %>
<h1>Edit article</h1>
<%= form_with(model: @article, local: true) do |form| %>
<% if @article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@article.errors.count, "error") %> prohibited
this article from being saved:</h2>
<ul>
<% @article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
<%= link_to 'Back', articles_path %>
ビューの場所に_form.html.erbというファイルを作ろう。
<%= form_with model: @article, local: true do |form| %>
<% if @article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@article.errors.count, "error") %> prohibited
this article from being saved:</h2>
<ul>
<% @article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
このファイルがパーシャル(部分テンプレート)になるみたい。
パーシャルを外出ししたので、new.html.erbとedit.html.erbの重複部分を変更しよう。
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
<h1>Edit article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
このように変更しても、new画面、edit画面は変わらず動作します。
_form.html.erbはnewやedit画面のフォームの部分をくり抜いたもののように見えます。
でもちょっと不可解なのは
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
<%= form_with(model: @article, local: true) do |form| %>
<%= form_with model: @article, local: true do |form| %>
このform_withの書き方のところ。
edit.html.erbとおんなじなんだけど、new.html.erbとは違う。
ということは、new.html.erbもこの書き方でフォーム作成できたってこと?
form_withの引数には、モデル名とか、アクションへのパスとかを書く。
model: @article
とかけば、new画面ならcreateアクションに、edit画面ならupdateアクションに飛べるってこと?
「このコードをよく観察してみると、form_withの宣言部分以外には元のコードとの違いがないことがわかります。他のフォーム内のコードを置き換えるパーシャル内でのform_with宣言がこのように短くて簡潔で済むのは、@articleがRESTfulルーティングの完全なセットに対応する リソース であり、必要なURIとメソッドをRailsがそれに基いて推測できるからです。 form_withの使用法について詳しくは、Rails APIのリソース指向のスタイル (英語) を参照してください。」
とガイドはおっしゃる。
Railsちゃんが推測しているんだと。
すげーな。