Partials allow you to easily organize and reuse your view code in a Rails application. Partial filenames typically start with an underscore (_) and end in the same .html.erb extension as your views.

Partial Basics

Creating a partial is easy. Simply create a new file that starts with an underscore. For controller specific partials, create the file in app/views/<controller_name>. For layout specific partials you can add the partial to the app/views/layouts folder.

For example, lets say we have a model called Posts in a blog we are writing. In our Posts controller we want to have both a new function and edit function. Rather than having two separate forms that need to be independently maintained and updated, we can have just one partial and include it in both views.

app/views/posts/_form.html.erb:



<%= form_for(@post) do |f| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% @post.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :title %><br />
    <%= f.text_field :title %>
  </div>
  <div class="field">
    <%= f.label :body %><br />
    <%= f.text_area :body %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Rendering a partial is done using the render method. Render allows you to render files within the view. The code below lets us use the form partial listed earlier in our new and edit views.

app/views/posts/new.html.erb:

<h1>New post</h1>

<%= render 'form' %>

<%= link_to 'Back', posts_path %>
app/views/posts/edit.html.erb:

<h1>Editing post</h1>

<%= render 'form' %>

<%= link_to 'Back', posts_path %>

The end result is that you can modify just one file, _form.html.erb to change your form for both the new and edit functions.

Another example is organizing code in the layout. You can do things like moving the html header code to it's own file. This is especially useful for larger layouts with hundreds of lines of code. To do this simply create a new partial and move the code to it. For example, the code below creates a partial called _html_header.html.erb and renders it from within the application layout.

app/views/layouts/_html_header.html.erb:

<head>
  <title>PartialsExample</title>
  <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true %>
  <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
  <%= csrf_meta_tags %>
</head>
app/views/layouts/application.html.erb:

<!DOCTYPE html>
<html>
<%= render 'layouts/html_header' %>
<body>

<%= yield %>

</body>
</html>

Global Partials

Sometimes you may want to make a partial accessible from anywhere. While you can easily reference the path of a partial (For example, layouts/html_header it can often be much easier to just make the partial global. To do this, create a new folder inside your views folder called application. Any partial you add to this folder can be referenced from anywhere. The previous example has been modified below to illustrate this feature.

app/views/application/_html_header.html.erb:

<head>
  <title>PartialsExample</title>
  <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true %>
  <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
  <%= csrf_meta_tags %>
</head>
app/views/layouts/application.html.erb:

<!DOCTYPE html>
<html>
<%= render 'html_header' %>
<body>

<%= yield %>

</body>
</html>

Variables in Partials

You can also pass variables to your partials. To do this you simply append the name of the variable and it's value to the render method. An example of this is listed below.

app/views/layouts/application.html.erb:

<!DOCTYPE html>
<html>
<%= render 'html_header', title: "Example App" %>
<body>

<%= yield %>

</body>
</html>
app/views/application/_html_header.html.erb:

<head>
  <title><%= title %></title>
  <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true %>
  <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
  <%= csrf_meta_tags %>
</head>

The long handed form of doing this would be <%= render partial: "html_header", locals: { title: "Example App" } %>.

Rendering Collections

Rails contains useful functionality for rendering collections. First, let's say we have a Product model. We can simply create a view called _product.html.erb, add in code to display the product, and make a single call to render the collection of products. This is accomplished by passing the instance variable itself as an argument to render: <%= render @products %>. Rails will automatically derive the model name from the collection and find the appropriate partial and render it. An example is below.

app/views/products/_product.html.erb:

<p>Name: <%= product.name %></p>
<p>Price: <%= product.price %></p>
app/views/products/index.html.erb:

<%= render @products %>

You can even render multiple different models with one render call. An example of how to do this is listed below.

app/controllers/contacts_controller.rb:

class ContactsController < ApplicationController
  def index
    @people = Person.all
    @businesses = Business.all
  end
end
app/views/contacts/index.html.erb:

<%= render [@people, @businesses] %>
app/views/people/_person.html.erb:

<p><%= person.name %></p>
app/views/business/_business.html.erb:

<p><%= business.name %></p>

The above example will look in app/views/people/_person.html.erb for the people collection and app/views/businesses/_business.html.erb for the business collection.

What if we want to share one partial across multiple models? For example, lets say we have two models, person and business, that both share similar field names. We can simply create a single partial to render them both! An example of this is listed below.

app/views/application/_contact.html.erb:

<p>
<%= contact.name %>
</p>
app/views/businesses/index.html.erb:

<%= render partial: "contacts", collection: @businesses, as: :contact %>

Layouts For Partials

Finally, you can specify a layout to use with each partial just like you can your views. To do this, simply pass the layout argument to render. For example: <%= render partial: "product", layout: "enhanced" %>.

That's it on our tutorial on partials, thanks for reading!