views:

177

answers:

5

Hello, I am fairly new to rails so I apologize if I am using the wrong terminology.

I have a model Menuitem that I would like to display the contents of in a layout. How does one go about passing an instance variable into a layout?

I was looking for a layout helper of some sort but I was unable to find anything. I was also looking at defining the instance variable in the application controller to access it in the layout, would this work? If so what is the best way to go about doing it?

Thanks!

A: 

Any instance variables defined in the controllers are auto-magically available in your views. If you are expecting an instance variable in your layout for all actions, you may want to consider defining the instance variable in a before_filter or encapsulating it in a controller method and using helper_method to make it accessible in your views.

Lytol
Could you elaborate on the before_filter concept? I have pondered using the helper_method but I think that only lets me use it in Views and not in the layout where I need it.
puttputt
helper_method allows the method to be used in the entire view layer including layouts, views, and helpers
Lytol
A: 

It really depends on what you want to do with the model. I'll just guess, and you tell me what you need different to understand better how to do this. This code would work only if your MenuItem model has a field named name.

In the controller:

# Use whatever action you are currently displaying
def index 
  @menu_items = MenuItem.all
end

In the index.html.erb view file:

<ul id="menu">
<% @menu_items.each do |menu_item| %>
   <%= h menu_item.name %>
<% end %>
</ul>

Obviously if this was a real menu, there would be hyperlinks there too :)

Doug Neiner
A: 

items_controller.rb (or something)

def show
   @menu_item = MenuItem.find(params[:id])
end

In the view show.html.erb:

<%= @menu_item.name %>
Garrett
+2  A: 

Two things I would note. First, you probably don't want to be doing this query every time you render any page in your application. You definitely want to cache your MenuItems. Second, it might be helpful to put a convenience method on MenuItems class to cache this value. So, if I define a method

def MenuItem.all_for_menu
  @@all_for_menu ||= MenuItem.find(:all)  #returns value if exists, or initializes it
end

I can call MenuItem.all_for_menu in my layout and get all the menu items. When ever you add a new one or edit one, you'd have to invalidate that.

Another caching approach would be to put the data in a partial and cache that fragment using the standard caching call:

<% cache(:controller => "menu_items",
         :action => "list", 
         :action_suffix => "all_menu_items") do %>
  <%= render :partial => "menu", :collection => MenuItem.all_for_menu %>
<% end %>

You can then expire that fragment by calling:

expire_fragment(:controller => "menu_items", :action => "list", :action_suffix => "all_menu_items")
MattMcKnight
+2  A: 

The usual way of passing variables up from the view into the parent layout is to use the content_for method. (This answer is a copy + paste from a similar answer I posted at this question)

The normal view content gets rendered automatically into the yield call without an argument in the layout. But you can also put other placeholder content in by using yield with a symbol argument, and specifying that content from the view with content_for.

app/views/layouts/posts_layout.html.erb

<html>
  <head>
    <title>My awesome site</title>
  </head>
  <body>
    <div id="someMenuStructureHere">
      <%= yield(:menu_items) %> <!-- display content passed from view for menu_items -->
    </div>
    <%= yield %> <!-- display main view content -->
  </body>
</html>

app/views/posts/index.html.erb

<%= content_for :menu_items, some_helper_to_generate_menu %>
<h1>Here is you page content</h1>
madlep