Need Advice: Structure of Rails Views for Submenus

Need advice: Structure of Rails views for submenus?

One thing you could play with is yield and content_for, used with a few partials for the menus. For example you could put each section of the menu in a partial and then modify your layout to something like:

<%= yield(:menu) %>

You then can then specify in your views content_for and put whatever partials you want into the menu. If it's not specified it won't get rendered.

<% content_for(:menu) do %>
<%= render :partial => 'layouts/menu' %>
<%= render :partial => 'layouts/search_menu' %>
etc...
<% end %>

If you're using a lot of the same menus in most pages, specify a default in your layout if no yield(:menu) is found.

<%= yield(:menu) || render :partial => 'layouts/menu_default' %>

Saves you a lot of typing. :) I've found this to be a nice clean way of handling things.

DRY view for sidebar

Rails provides a helper called controller_name which you can read more about here.

Assuming you adhere to your own naming conventions, this should work as-is. If you decide some controllers don't get a sidebar, you may need to throw in some conditionals...

application.html.erb

<div class="side">
<%= render "layouts/sidebar" %>
<%= render "layouts/sidebars/#{ controller_name }" %>
</div>
<div class="main-content">
<%= yield %>
</div>

EDIT
Sorry, my mistake was using single quotes instead of double-quotes. You cannot use #{string interpolation} within single quotes. Source

How do I implement Section-specific navigation in Ruby on Rails?

You can easily do this using partials, assuming each section has it's own controller.

Let's say you have three sections called Posts, Users and Admin, each with it's own controller: PostsController, UsersController and AdminController.

In each corresponding views directory, you declare a _subnav.html.erb partial:


/app/views/users/_subnav.html.erb
/app/views/posts/_subnav.html.erb
/app/views/admin/_subnav.html.erb

In each of these subnav partials you declare the options specific to that section, so /users/_subnav.html.erb might contain:

<ul id="subnav">
<li><%= link_to 'All Users', users_path %></li>
<li><%= link_to 'New User', new_user_path %></li>
</ul>

Whilst /posts/_subnav.html.erb might contain:

<ul id="subnav">
<li><%= link_to 'All Posts', posts_path %></li>
<li><%= link_to 'New Post', new_post_path %></li>
</ul>

Finally, once you've done this, you just need to include the subnav partial in the layout:

<div id="header">...</div>    
<%= render :partial => "subnav" %>
<div id="content"><%= yield %></div>
<div id="footer">...</div>

Multi level menu, active links css highlight. (Ruby on Rails)

I wouldn't recreate the wheel and use a Rails menu-builder gem/plugin like simple-navigation.

Here's a demo of navigation and styling.

Is there anyway to add another levels of menus with Active Admin?

I got fix this problem overwriting the menu of ActiveAdmin. It was also necessary create a new CSS to the new menu.

Inform the ActiveAdmin that we will use a header itself. To this add the following lines in the file config/initializers/active_admin.rb:

config.view_factory.header = CustomAdminHeader
config.register_stylesheet 'new_menu.css'

Create a class called CustomAdminHeader that will contain the code that will overwrite the construction menu. You can create this class within the app/admin and name the file as custom_admin_header.rb. And add this code to create the new menu:

class CustomAdminHeader < ActiveAdmin::Views::Header
include Rails.application.routes.url_helpers

def build(namespace, menu)
div :id => 'tabs' do
# Add one item without son.
ul do
# Replace route_destination_path for the route you want to follow when you receive the item click.
li { link_to 'Item without son', route_destination_path }
end

# Add one item with one son.
ul do
li do
text_node link_to("Parent with 1 child", "#")
ul do
li { link_to 'Son without child', route_destination_path }
# If you want to add more children, including more LIs here.
end
end
end

# Adds a menu item with one son and one grandson.
ul do
li do
text_node link_to("Grandmother with 1 child", "#")
ul do
li do
text_node link_to("Parent with 1 child", route_destination_path)
ul do
li { link_to 'Grandson without child', route_destination_path }
# If you want to add more grandchildren, including more LIs here.
end
end
end
end
end

super(namespace, menu)
end
end

The structure of your menu will be created by this class so the menu settings used in the classes contained in the folder app/admin should not be displayed. For this you need to add the following code in all classes:

menu false

Finally you need to create a CSS file called new_menu.css and add the CSS for the new menu.

I posted this solution at my blog:

http://monteirobrena.wordpress.com/2013/05/07/activeadmin-customizacao-do-menu/

I hope it's helpful for anyone.

Rails 3 - Loading a Subnav with Ajax.... Which controller owns a subnav?

For me, I would use a navigation controller rather than the application controller as the application controller growths extremely complex easily.

This should create a view folder in app/views/navigation. I would also put all my navigation templates here (including you main nav).

So there might be those files:

app/views/navigation/
_main_nav.html.erb # made it a partial file for including in other pages
subnav.html.erb # or subnav.js.erb if you don ajax call and return scripts

and in your layout files, where you want the main nav, you just render it.

So even tomorrow you suddenly want two or three different navigation menus, and there ajax calls, you have a centralized place to handle them, instead of putting them all inside the application controller.

Another more suggestion is, generate the navigation controller under some scopes. Like app/controllers/page_structures/navigation_controller.rb, so your views will be in app/views/page_structures/navigation/

In this way, you could put all your page structure related things like sidebars, custom headers, banners, etc inside the same scope page_structures.

===== UPDATE =====

Since your AJAX calls seems relatively static, I would suggest your paths use some kind of direct match.

If my guess correct, your top navigation have some items, and each item has their own sub-menu. So you will want to load the sub-menu one by one but not all. (If actually it's all, then you could just include them all in rendering...)

/page_structures/:top_nav/:sub_nav_template_name # So in here I assumed you will have many navigations and sub-nav to load.

then we match this path to the following action:

def get_sub_nav
# checks both params[:top_nav] and params[:sub_nav_template_name] exist and not pointing to some other dangerous place. (I don't know if this work if the input is './' or '../' these kind of things
render "page_structures/navigation/#{params[:top_nav]}/#{params[:sub_nav_template_name]}"
end

By this simple action, whenever you added more navigation / navigation items, you just need to create the corresponding AJAX response template. in this way, you are doing the minimal things!

Of course, if some how you have some items will need to return some other data as the response, such as responding sub-categories, you may need to create other routes to let you pass your parent category id.

You could think like that: my suggestion is for the default relatively static centralized sub-nav
But if you need some specialized sub-nav, which need other data to process, for each one you will have to create a route and an action in the navigation controller to accept your category id, product id, etc. But still, these template file could following the same filing way.

Reasons for not having a compact structure of an MVC application?

It all depends on what you want to achieve, and what your workflow is. You seem to be working in PHP - it's worth looking at non-PHP frameworks like Ruby on Rails.

Typically, you want an output folder to be "read-only" - the developer should not manually edit files, instead the build and deploy pipelines run tools like Gradle to convert SASS/LESS and JS files (from the /source folder) into CSS and minified/concatenated Javascript and place them in the correct location in /public. The build and deploy pipelines often have different configs for development and production builds (minifying only for production, for instance).

In Ruby on Rails, the structure is mostly as you describe as "much better" - except that "templates" is a folder underneath "views" called "layouts". There's a build step (which runs automagically) which converts the various asset files (SASS/LESS, JS etc.).

You can see a detailed description of the Ruby on Rails directory structure here. Django's directory structure is explained here.

Answering the questions in your comments:

  • Where should the SASS/LESS/JS/Coffee script files go? - Up to you. In Rails, they live in /app/assets/javascripts and /app/assets/stylesheets; in these folders, there is one file for each view, as well as application-level files. This makes your build process nice and simple - you have just 2 folders to worry about, and don't have to modify your build every time you create a new view.
  • How do I structure my views - I have application-level views and specific page views. Again - mostly a question of convenience. In Rails, all the templates - live under /app/views. Application-level views live in a folder called /app/views/layouts - they are really not that different to the page-level templates, so moving them out of that folder doesn't seem to achieve very much, whereas keeping everything in the same top level folder makes build and configuration simpler.

So, no, there's no reason to do what you suggest.



Related Topics



Leave a reply



Submit