Partial Template 2020
Often, we have parts of pages that we want to use in multiple places. These could be standard page elements, such as headers and footers that can be used in multiple layouts. Or they could be items, such as advertisements for specific pages. Rails facilitates both of these situations with a partial template (or just partial).
A partial is a view template that is supposed to be included in another template, or in a layout. In either a template or a layout, we can simply include a partial by reference, with a statement that reads render :partial, and then the name of the partial as shown below:
render :partial => 'name_of_the_partial'
We can also use a partial when we want to repeatedly insert the same bit of markup, but using data from a series of objects.
For example, consider our listing of post instances. We can use a partial that displays the information for a single post. We could simply put that partial in a loop that executes it once for each post object, like this:
<% for post in posts %> <%= render :partial => 'post' %> <% end %>
Rails gives us a shortcut that makes this even simpler: in the render :partial statement, we can refer to the array of post objects (which the controller provided), and the partial will automatically be repeated for each post in the array as shown in the code below:
<%= render :partial => 'post', :collection => posts %>
Here is an example from the "blog" app in Getting Started with Rails.
The "Blog"s edit page looks very similar to the new page:
edit page:
new page:
In fact, they both share the same code for displaying the form.
So, we want to remove this duplication by using a view partial. By convention, partial files are prefixed with an underscore.
Let's create a new file app/views/articles/_form.html.erb with the following content:
<%= form_for @article do |f| %> <% 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> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %>
Everything except for the form_for declaration remained the same.
The reason we can use this shorter, simpler form_for declaration to stand in for either of the other forms is that @article is a resource corresponding to a full set of RESTful routes, and Rails is able to infer which URI and method to use.
Here is the old app/views/articles/edit.html.erb:
<h1>Editing article</h1> <%= form_for :article, url: article_path(@article), method: :patch do |f| %> <% 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> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %>
This will be replaced with this one which uses _form.html.erb partial template:
<h1>Edit article</h1> <%= render 'form' %> <%= link_to 'Back', articles_path %>
Same to app/views/articles/new.html.erb, and the new one looks like this:
<h1>New article</h1> <%= render 'form' %> <%= link_to 'Back', articles_path %>
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization