Partials as reusable components

There is often a need to extract common markup for reuse, and partials are the best way to do that. We like to think of reusable markup as components because the markup is rendering data, and it’s this combination of dynamic input and rendering that feels like more than just copying HTML elements around. To make partials effective and sustainable at managing reusable components, there are two guidelines that help:

  • Do not use partials for any purpose other than reusable components.
  • Partials should use locals for parameters, not instance variables.

Before we get into these guidelines, we want to talk about why we are not recommending layouts and helpers for this purpose.

Don’t use layouts for reusable components

Layouts are most useful for global cross-cutting concerns like the inclusion of stylesheets or a site-wide navigation bar. Although Rails allows us to use different layouts when needed, it’s hard to nest layouts or compose them in a flexible way.

Apps often end up with an application layout that has a lot of conditional content in it using yield and content_for, and as a mechanism for markup reuse, it’s fairly limited. We are not saying we shouldn’t avail ourselves of layouts when needed, but it shouldn’t be your go-to tool for reuse. We should avoid building a lot of content in helpers. Instead, use partials.

Use partials for reusable components only

In a complex Ruby class, we often extract private methods from public methods to make the public method more readable. This functional decomposition can greatly help navigate complex routines. The fact that the methods extracted are private means we don’t have to worry about supporting these methods as a new public API. It allows us to get the benefits of extracting complexity without the drawback of having to test, support, and version new public methods.

There is no such thing as a private partial in Rails. When we extract a partial, any other view can use it, even if the partial wasn’t designed for reuse. Because partials can’t define an API for how to reuse them, it creates a situation where brittle code can be repurposed inadvertently.

The downside of this convention is that we don’t end up using partials merely to extract complexity. This is a trade-off, but we believe it’s the right one. By using partials only for reusable components, it’s easy for everyone to decide when to use a partial, as well as to understand what a partial is for when they come across one. Of course, authoring a partial to be reusable is tricky, as is keeping it reusable when we need to change it. Using semantic HTML can help somewhat, but what helps much more is to be explicit about what data should be passed into the partial. That means we should not use instance variables but instead use locals.

Use locals to pass parameters to partials

We discussed how confusing it can be to use multiple instance variables to communicate from a controller to a view. This same logic applies to partials, especially given their role as reusable components. Suppose we extract the widget rating UI as a reusable component. First, we’ll copy the component to its own file in app/views/widgets/, called _rating.html.erb:

Get hands-on with 1200+ tech skills courses.