1

I'm currently going through the Rails Views book, Ch 1 - Layouts, and can't figure out why I keep getting the following error message:

undefined local variable or method `current_tab' for #`
Extracted source (around line #4):
1: <% content_for :main_navigation do %>
2: <nav id="main_nav" role="navigation">
3:  <ul>
4:      <%= nav_tab 'Home', root_path, current: current_tab %></li>
5:      <%= nav_tab 'Creations', creations_path, current: current_tab %></li>
6:      <%= nav_tab 'Campaigns', campaigns_path, current: current_tab %></li>
7:      <%= nav_tab 'Projects', projects_path, current: current_tab %></li>

app/views/layouts/_main_nav.html.erb:4:in `block in _app_views_layouts__main_nav_html_erb__163583644_37720476'
app/views/layouts/_main_nav.html.erb:1:in `_app_views_layouts__main_nav_html_erb__163583644_37720476'
app/helpers/navigation_helper.rb:9:in `currently_at'
app/views/static_pages/home.html.erb:1:in `_app_views_static_pages_home_html_erb___39106558_37242780'

Here are the relevant files in the mix:

Application.html.erb

<body>
    <%= render 'layouts/header' %>

_header.html.erb

<header id="page_header" role="banner">
    <nav id="utility">
        <p>
            You are logged in as <strong>Mat Bloody Cauthon</strong>
            <%= link_to "[Your Account]", "#" %> |
            <%= link_to "[Logout]", "#" %>
        </p>
    </nav>
    <%= link_to(image_tag("logo.png", alt: "Artflow", id: "logo"), root_url, title: "Dashboard") %>

    <%= yield :main_navigation %>
</header>

_main_nav.html.erb

<% content_for :main_navigation do %>
<nav id="main_nav" role="navigation">
    <ul>
        <%= nav_tab 'Home', root_path, current: current_tab %></li>
        <%= nav_tab 'Creations', creations_path, current: current_tab %></li>
        <%= nav_tab 'Campaigns', campaigns_path, current: current_tab %></li>
        <%= nav_tab 'Projects', projects_path, current: current_tab %></li>
        <%= nav_tab 'Designers', designers_path, current: current_tab %></li>
    </ul>
</nav>
<% end %>

navigation_helper.rb

module NavigationHelper
    def nav_tab(title, url, options={})
        current_tab = options.delete(:current)
        options[:class] = (current_tab == title) ? 'active' : 'inactive'
        content_tag(:li, link_to(title, url), options)
    end

    def currently_at(tab)
        render 'layouts/main_nav', locals: {current_tab: tab}
    end
end

home.html.erb (root_path)

<%= currently_at 'Home' %>

I'm really trying to understand the order in which Ruby is loading things as I think that might be part of it. Here's the flow as I understand it:

  1. User navigates to root page (home.html.erb)
  2. Application.html.erb loads, rendering _header.html.erb partial
  3. _header.html.erb yields _main_nav.html.erb via :main_navigation
  4. _main_nav calls nav_tab() from navigation_helper.rb to set up the links
  5. Back to Application.html.erb which yields home.html.erb
  6. Home calls currently_at() from navigation_helper.rb which renders the _main_nav.html.erb partial, which should show the navigation on the current page.

Is this progression correct? If so, why is rails choking on currently_at, which looks like it sets current_tab?

JStandard
  • 53
  • 8
  • @DaveNewton current_tab is a local to the `main_nav` partial, which is passed to and extracted from the helper. – Chris Heald Jul 03 '13 at 00:02
  • @ChrisHeald Oh, there it is-missed it. – Dave Newton Jul 03 '13 at 00:09
  • Found the problem. It turns out the problem was with trickiness in using `render` as shorthand for `render partial:` in my `currently_at` function. Just using `render` apparently ignores local variables being passed, so I needed to use the full syntax `render partial:` – JStandard Jul 03 '13 at 03:00
  • Too points poor yet to answer my own question, will post this here for later: – JStandard Jul 03 '13 at 03:05

1 Answers1

1

Turns out the problem was that in my currently_at(), the line:

render 'layouts/main_nav', locals: {current_tab: tab}

ignores the local variables being passed since it's using a shorthand version of render partial:

Changing this line to:

render partial: 'layouts/main_nav', locals: {current_tab: tab}

fixes the problem.

This question helped me come to my senses: Render @object and locals vs render :partial

I appreciate those who took a look, now we can all go enjoy a beer for our troubles. (at least that's my plan)

Community
  • 1
  • 1
JStandard
  • 53
  • 8