htmlruby-on-railsruby-on-rails-4nestedlayout

Nested layout inside application layout


I have little problems with nested layouts. On my site I need to make one separate part of the site only for administrator.

I have this in my application.html.erb file:

<body>
    <%= render 'layouts/header' %>
    <div class="container">
        <%= yield %>
        <%= render 'layouts/footer' %>
    </div>
</body>

I was wondering how can I now make another template like this to be inserted inside <%= yield %> because for administrator part I again need fixed parts of the site like header and footer in main layout. Instead of header and footer I will have two menus. I want <%= yield %> to be filled with new template which will have menu on top and new <%= yield %> which will be filled with actions from admin controller. So, menu will always stay on top.

I've made a menu partial views/admins/_menu.html.erb:

<div>  
    <div>  
        <div class="container">  
            <ul>
                <li><%= link_to "Action1", '#' %></li>
                <li><%= link_to "Action2", '#' %></li>
                <li><%= link_to "Action3", '#' %></li>
            </ul>
        </div>  
    </div>  
</div> 

My new layout is layouts/sublayouts/admin.html.erb:

<%= render 'admins/menu' %>
<%= yield %>

Currently alternative is to render views/admins/_menu.html.erb in each view on top but that doesn't look as a good solution to me.

Regular site would have this structure:

Header/Menu
   |
Container
   |Content
Footer

And admin site would have this structure:

Header/Menu
   |
Container
   |Content
     |Admin Menu
     |Admin Content
   |
Footer

What would be the best way to accomplish this?


Solution

  • Update: Based on the comments I've updated the answer with a better understanding of the question

    The best way is to incorporate this into your application.html.erb layout.

    The desired behavior is to have the admin menu appear when the user clicks on the Admin Panel link or any links on the admin menu.

    The way I recommend doing this is that you have an admin controller which handles routing to all of your admin views, so clicking on the Admin Panel button and all the links in the admin menu will be handled by your admin controller. Add a before_filter to you admin controller like this:

    # app/controller/admin_controller.rb
    class AdminController < ActionController::Base
      before_filter: set_admin_status
    
      private
      def set_admin_status
       @admin = true
      end
    end
    

    In your application template do the following:

    # application.html.erb
    <body>
        <%= render 'layouts/header' %>
        <div class="container">
            <% if @admin %>
              <%= render 'admins/menu' %>
            <% end %>
            <%= yield %>
            <%= render 'layouts/footer' %>
        </div>
    </body>
    

    What this should do is that everytime you navigate to the page that corresponds to the Admin Panel or any of the links in your admin menu it will set the @admin_status flag to be true and your layout will render the admin menu, which I believe is the desired behavior.