An Intro to Partials and Helpers in Ruby on Rails

Source: undraw.co

After college I coordinated volunteer groups at a shelter for families experiencing homelessness. The largest service day involved coordinating assignments for 70 volunteers. The shelter had mostly smaller rooms, so I split the group up, with each subgroup working in a separate space on a separate task. This division of work allowed us to accomplish a range of discrete projects while not jamming the halls with lots of movement between rooms or requiring the same project instructions to be repeated from one room to the next.

This highly-organized day came to mind recently as I was building a Ruby on Rails app that helps users track volunteer engagements at their organization. Rails favors conventions that lend organization to applications and uses a Model-View-Controller (MVC) architecture that separates application responsibilities into three distinct layers:

  • Models handle the data and domain logic
  • Views handle presentation and how information is displayed to users
  • Controllers serve as the intermediary between views and models as they relay user requests to the model for processing and pass on model responses to the views for display

As part of this separation of concerns, views and models don’t directly interact. Models don’t handle how information is displayed, and it’s generally best practice to keep logic out of your view files as much as possible.

In this post we’ll explore how Rails partials and helpers can help us follow the ‘Separation of Concerns’ principle of software design while also avoiding repetition and keeping our views DRY. We’ll use snippets from the volunteer application as examples.

Helpers

What are helpers?

Helpers are methods that allow you to encapsulate tasks for reuse throughout your views. They can also help you extract logic from your views, like conditional statements. Rails provides handy pre-built view helpers that assist with common tasks like building forms and creating HTML links. If the built-in helpers don’t fit your needs, you can also build your own custom helper methods.

Where to store custom helpers

Custom helpers are typically stored in the app/helpers directory and organized into modules named after your controllers. In the volunteer application, for example, I created a VolunteersController and a volunteers_helper.rb file that contains a VolunteersHelper module. This module stores my custom helper methods for displaying volunteer-related data.

While you can use the helper methods defined in the app/helpers directory in any view, separating the helper methods into different modules and files based on how they’re used can make development and debugging easier.

There might be a helper method you want to use in multiple views. In this case, Rails provides an ApplicationHelper module (found in application_helper.rb) where you can store helpers that span multiple categories.

Examples

1: link_to - In the volunteer tracking application, I made frequent use of the built-in Rails helper method link_to. This method is handy for setting up links in your views and lets you make use of the path/url helpers Rails provides when you set up routes.

This snippet generates the following HTML:

2: image_tag - Along with a helper for generating links, Rails provides a helper for displaying images. The image_tag helper generates a HTML image tag with the resource specified. This tag came in handy for inserting an image placeholder into volunteer profile pages.

This snippet generates the following HTML in the browser:

Rails also has extensive helpers for form building along with helpers for formatting currency, formatting phone numbers, and more url/link related helpers.

Side note: If you’re looking for beautiful open-source illustrations, check out Undraw.co.

Partials

What are partials?

Partial templates help you package chunks of code for reuse in your views. Partials are a good fit for code you find yourself repeating, like a snippet you want to display for each item in a collection.

In the volunteer app, for example, I used the same form structure to create a new volunteer record and edit an existing volunteer record. Rather than creating the form twice, I created the form once as a partial and rendered it in both volunteers/new.html.erb and volunteers/edit.html.erb.

Where to store partials

Partial file names start with an underscore, like _volunteer.html.erb. They’re typically organized into view folders based on which views use them. Continuing the volunteer form example, I stored the form partial in my app/views/volunteers directory since I would be using it in only volunteer-related views.

You can set up a shared folder in your app/views directory to hold partials you use across your application, such as error messages.

Partials in use

Rendering a partial:
The render method lets you incorporate your partials into your views. If you’re rendering the partial in a view that’s located in the same view folder as the partial, you can simply reference the partial by name (without the leading underscore):

app/views/volunteers/new.html.erb

If you’re rendering a partial from another folder, be sure to include the folder name too (still no leading underscores needed):

app/views/volunteers/new.html.erb

Partials with locals

For greater flexibility, partials can be set up with local variables. In the volunteer app, if a user submits a form to create a volunteer, role, or activity record that contains invalid data, the app displays Rails’ standard validation error messages above the related form so users will know how to adjust the input before resubmitting.

Since I wanted the code to work for any object (e.g., volunteer, role, activity record), I set up a _validation_errors.html.erb partial in the views/shared directory using a local variable named object.

views/shared/_validation_errors.html.erb

To render this partial in my views/volunteers/new.html.erb template, we must pass in a value for object. What value though?

In my VolunteersController’s new action, I instantiated a new volunteer object, @volunteer, for the user to add attributes to via the ‘new volunteer’ form. If the user fills out the form in a way that meets all the validations/criteria set up in my Volunteers model (e.g., a volunteer must have a full name, must have a contact method), then the new volunteer record will be saved to the database. If not, Rails will add error messages to my @volunteer object, so I’ll need to pass @volunteer to the partial to access these messages.

views/volunteers/new.html.erb

Over in the template for making a new role things work the same way:

views/roles/new.html.erb

And in the template for creating a new activity:

views/activities/new.html.erb

Rendering Collections with Partials

One way to extract iteration logic from your views is to use a partial and specify a collection option. Rather than including the following loop directly in the volunteers index template, this can be refactored with a partial.

Loop in the index view:

Loop directly in volunteers index view — views/volunteers/index.html.erb

Refactored with partial:

Partial — views/volunteers/_volunteer.html.erb
Refactored volunteer index with partial — views/volunteer/index.html.erb

Bonus: Spacer Templates

If you want to add a specific element between each item of a collection, like a horizontal rule or a comma, you can use Rails’ spacer template option when rendering your collection.

Example:

In the volunteer app, each volunteer’s profile page displays a list of all the volunteer roles they’ve engaged in. Each role is displayed as a link to that role’s show page, and the list is separated by commas.

First we set up a partial with a local variable, role, for the role links:

views/volunteers/_role_links.html.erb

Then we create possibly the simplest file ever to serve as the spacer template:

views/shared/_comma.html.erb

Now the partial and spacer template can be combined to display the list in the profile page:

views/volunteers/show.html.erb

Keep learning

Partials and helpers are handy tools for DRYing out your Rails app and separating concerns. We’ve explored some of the basic applications and syntax here. If you want to keep learning, the Rails docs provide more examples and details on the methods and options available to you. Check them out!

Software engineer interested in the intersection of tech, design+art, and social innovation