Winding road

Passing Variables to Partials

Sunday February 26, 2017

While working on a new feature for this site (which you can now see at the bottom of the post), I came up against a challenge where I wanted to create a contributors component that would be shown in both the posts#show and contributors#index views for my posts. This feature shows who wrote the post, and gives some information about that person. The component is contextual to the post in which contained it, while the index view would list all variations of that component.

The problem:

The challenge here is that the index and show views have access to different variables, and use them in different ways. Namely, the index gets a @contributors instance variable which references all the contributors at once. The show view has access to @contributor, which references a specific contributor. Let's take a look at some code to illustrate. I'm showing the erb code without HTML tags to keep it simple:


# contributors/index.html.erb
  <% @contributors.each do |contributor| %>
    <%= image_tag contributor.avatar.url(:thumb), class: "avatar" %>
    Written by <%= contributor.name %>
    <%= contributor.bio %>
    <%= contributor.site %>
    <%= contributor.twitter %>
  <% end %>

# posts/show.html.erb
  <%= image_tag @contributor.avatar.url(:thumb), class: "avatar" %>
  Written by <%= @contributor.name %>
  <%= @contributor.bio %>
  <%= @contributor.site %>
  <%= @contributor.twitter %>

I wanted a way to build only one contributor card, and be able to use it in both views, if not more, so that the styling and composition is always consistent. The best way would be to move the core content into a partial, and then render that partial in each view.

I made a partial called _contributors_card.html.erb inside of the views/contributors folder. The contents of the file look something like:


# contributors/_contributors_card.html.erb
  <%= image_tag contributor.avatar.url(:thumb), class: "avatar" %>
  Written by <%= contributor.name %>
  <%= contributor.bio %>
  <%= contributor.site %>
  <%= contributor.twitter %>

Note that these are not instance variables, and lack the @ symbol. This will help us later when using the partial in different views. I removed the duplicate code from the previously mentioned views, and replaced it with a render:


# contributors/index.html.erb
  <% @contributors.each do |contributor| %>
    
    <%= render partial: 'contributor_card', locals: {contributor: contributor} %>

  <% end %>

# posts/show.html.erb
  <%= render partial: 'contributors/contributor_card', locals: {contributor: @contributor} %>

Using locals: we can pass in a hash of available variables, and reassign them to work within the partial. Now if I decide to change the markdown for the contributor card, and I can do so in one place without worrying about breaking anything.

Robinheadshotsquare

Written by Robin Hamill

Robin is an independent web application and ecommerce developer living in Toronto. He builds intuitive and functional web apps that engage users and solve problems. He's also excited about climbing rocks, travelling and learning all the things. 💎⛪️

Back