Partials
On the site's navigation bar, add a link to the About page.
Straightforward about link:
<%= link_to "About", about_path %>
Move the "About" link to the right side by wrapping it an div with the skeleton's simple u-pull-right
class.
Here's the code:
application.html.erb
...
<div class="container">
<div class="u-pull-right">
<%= link_to "About", about_path %>
</div>
The file application.html.erb
is getting a little messy, so it would be good if we could separate out the entire header into its own file. In Rails, you can do this with partials. They are files that are called from within templates to insert additional content. Partials are like other view files, but they are marked with an underscore _
at the beginning of their name. It's time to clean things up:
- Create a new file in layouts called
_header.html.erb
. - Cut out the header code from application.html.erb and paste it into your new header file.
layouts/_header.html.erb
<header class="navbar">
<%= link_to "Home", root_path %>
<div class="u-pull-right">
<%= link_to "About", about_path %>
</div>
</header>
3. To render this file in application.html.erb, use the render
method:
...
<body>
<div class="container">
<%= render 'layouts/header' %>
This will render the contents of the _header
file. Note that you render header
without an underscore. When Rails sees render
, it knows to look for a partial, so it will automatically render the file named _header.html.erb
. Now that we cleaned up application.html.erb, let's see how partials can be even more useful.
_product partial
We used very similar code in both the products index page and the category show page. This violates the Rails principle of DRY - Don't Repeat Yourself. It's harder to maintain code when the same code is repeated in different areas. In regular programming (such as on the Rails backend), repeated code is usually moved to a method that can be called from multiple areas. But you don't usually use methods to display HTML in the front-end, so how can you avoid duplication?
The same Rails partial can be called from different templates so you avoid re-writing the same code. Let's create a partial for displaying the basic information about a product.
Create a file in products
called _product.html.erb
/products/_product.html.erb
<li><%= link_to product.name, product %></b></li>
We can now improve our list of products by using a partial:
/categories/show.html.erb
<ul>
<% @category.products.each do |prod| %>
<%= render 'products/product', product: prod %>
<% end %>
</ul>
Note how this call to render includes something new at the end: product: prod
.
This code assigns prod
to the variable product
and sends product
to the partial. The partial can then refer to product
which has a different value each time. You can pass variables to partials so they can render different variables, different instances of a model, or even multiple models.
Rails actually provides a shortcut when rendering the partial that shows an item:
<ul>
<% @category.products.each do |product| %>
<%= render product %>
<% end %>
</ul>
Since product
is an instance of a model, Rails will automatically display the partial named _product
when you render it.
You can even get rid of the loop and rely entirely on Rails magic:
<ul>
<%= render @category.products %>
</ul>
In the above code, Rails will go through the given collection and render the file with the same name (_product) for every item in it.
Now that you've shortened the categories show page, go ahead and do the same thing for the products index page.
Do the same thing as before, but render @products
directly this time:
<h1><%=@title%></h1>
<ul>
<%= render @products %>
</ul>
Check out your /products page. It should look the same as before, but now it's using much more efficient code!
Let's say we realized that we should include the price information wherever the product is displayed. Before our refactoring, we would need to manually change each place to display the price, but now we can just change the product partial. Go ahead and change the partial so the price is displayed.
Simply add the price, with a $ sign before it:
<li>
<%= link_to product.name, product %>
$<%= product.price %>
</li>
You can now check that both the products/index and categories/show pages have been updated.
Challenge
What should you do to avoid duplicating HTML (and embedded Ruby) in multiple Rails templates?
Please sign in or sign up to submit answers.
Alternatively, you can try out Learneroo before signing up.