This is in relation to an older post about tabbed navigation. No matter the implementation, I always seem to match controller names with tab/link/section names. But I’m realizing that’s simply too coupled.
These days, I name my controllers in the context of a resource. And now that I’m adopting namespaces for privileged access, it’s likely that I’ll have controllers having the same controller_name but different intentions, and I wouldn’t necessarily want a section highlighted in both cases. Besides, adding a controller should not force me to consider a tab, or navigation at all for that matter. It’s more important that it makes sense within the code base.
So I’ve updated my implementation.
# views/layouts/application.html.erb navigation :home, :projects, :about, :contact, :admin # helpers/application_helper.rb def navigation(*links) items = '' links.each do |link| css = (link == @current_tab ? 'current' : '') link != :admin ? items << tab(link, css) : (items << tab(link, css) if logged_in?) end content_tag :ul, items end
The tab(link, css) helper just constructs the link. And to set the current tab:
# controllers/application.rb class ApplicationController < ActionController::Base before_filter :set_current_tab protected def set_current_tab # will default to controller_name if @current_tab # has not been set by another controller @current_tab ||= controller.controller_name.to_sym end end # override the 'set_current_tab' method in any controller # if a name other than the controller_name is desired # # For example: # controllers/admin/authorized_controller.rb class Admin::AuthorizedController < ApplicationController before_filter :authenticate protected def set_current_tab @current_tab = :admin end end
By implementing the tabs this way I’ve banned the directory authentication and reverted back to an AuthorizedController, as that allows me to easily authenticate and set the admin tab for all administrative controllers.
Another solution would be to leave it as it were and override controller_name, but that didn’t feel right since it would’ve completely distorted the point of the controller_name in the first place. And so I didn’t do it.
It’s not like this is rocket science, I just thought I’d give an update.






Comments
It may not be rocket science, but it sure makes my code look like a 5th grade science project. :^)
Let’s take this even further:
Of course, none of this was tested, but you get the idea ;-)
I like it… thanks.
Be sure to let me know when slate goes open-source… I think I could learn a lot browsing through your code.
Just a note – this is actually a really good idea in general. In the past, I’ve tried to make the active tab all smart and fancy, but then you inevitably run into an edge case that forces you to add a weird option (like :matches in my case).
Setting the current tab in the controller, while it does require a little configuration, is much easier to maintain.
Just thought I’d share that I like the idea so much I’m refactoring slate to implement it.
Shouldn’t the “controller.controller_name.to_sym” be “self.controller_name.to_sym” ? in controllers/application.rb.
Well,
controllerwill actually return the current controller (self) since it will run up the hierarchy and immediately find itself.But yes, for good form it probably should be
self.controller_name(orself.to_s.gsub(/Controller$/, '')), as that would be the safer way to go for a mixin/plugin.