3

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?

user3304086
  • 901
  • 1
  • 9
  • 19

2 Answers2

1

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.

alalani
  • 507
  • 4
  • 13
  • Looks good but how would I accomplish for that menu to show up only when I click on button which opens view where is admin menu? Currently it will show up immediately on the front page together with all content. – user3304086 Feb 14 '14 at 18:50
  • Can you clarify a little bit: do you want the admin to navigate to an admin page (so there is only one view where you render the admins/menu partial), or do you have an entire admin section which is a series of pages (so there are multiple views where you load this partial)? – alalani Feb 14 '14 at 19:10
  • Ok :) Inside header I have menu with links (Admin Panel, Link2, etc). After user clicks on Link2, content for link displays on the place of `yield`. But after user clicks on Admin Panel, new menu with links (AdminMenuLink1, etc) shows inside `yield`. Now I have two menus! After admin clicks on AdminMenuLink1, content is displayed below but the 2nd menu is still there. Menu should always be there if user navigates only on links (AdminMenuLink1, etc) which are inside that menu2. If admin clicks on a Link2 from the first menu, he exits admin menu and see normal content again without 2nd menu. – user3304086 Feb 14 '14 at 19:23
  • ok I think I get what you are talking about. Let me update my answer for that. – alalani Feb 14 '14 at 19:29
  • Yes, this works! Thank you. Now the only thing I need to figure out is how to leave that menu if I need some Views which are handled with other controllers. Same trick with `set_admin_status` won't work anymore. – user3304086 Feb 14 '14 at 20:04
1

Usually I do following to accomplish the same problem, I create the separate layout based on parent class:

application_controller.rb

class ApplicationController < ActionController::Base    
  protect_from_forgery
  layout :layout

  private
  def layout
    if self.class.parent == Admin
      'application_admin'
    else
      'application'
    end
  end
end

app/views/layouts/application.html.haml

Header/Menu
   |
Container
   |Content
Footer

app/views/layouts/application_admin.html.haml

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

Update 1


config/routes.rb

namespace :admin do
  root to: 'home#index'
  resources :admins
end

app/controllers/admin/admins_controller.rb

class Admin::AdminsController < ApplicationController
  def index
    // code
  end
end
Said Kaldybaev
  • 9,380
  • 8
  • 36
  • 53
  • I don't have success with this code. This line `if self.class.parent == Admin` compares is the name of current controller "Admin"? In my case I set `if self.class.parent == AdminsController`. – user3304086 Feb 14 '14 at 18:38
  • @user3304086 I've updated post, shortly you should move your `admins_controller.rb` to the `app/controllers/admin` namespace – Said Kaldybaev Feb 14 '14 at 18:46
  • Hmm, now I receive the following error: `Could not render layout: uninitialized constant ApplicationController::Admin` – user3304086 Feb 14 '14 at 19:01
  • It's same as yours. It says that's a NameError in my main controller from which I control all static pages. Not in AdminsController.. – user3304086 Feb 14 '14 at 19:33