Tutorial for Adding Tabs to Rails Using Tabulous

Step-by-Step Tutorial for Creating a Tabbed Rails Application

This tutorial shows you how to make a simple Rails application from scratch that has both tabs and subtabs.

Update: This blog post is about an old version of tabulous. Tabulous 2 has a completely different syntax. This tutorial should still work except for the parts referring to the app/tabulous/tabulous.rb file. Read more about the new version of tabulous.

Step 1: Scaffolding the Application

Let’s say you want to keep track of all the fonts you like and all of the design-related websites you think are cool. And let’s also say that you don’t believe in using a simple text file but feel compelled to build an entire Rails app just for this purpose. (Who said this wasn’t going to be contrived?)

First, start by creating a Rails 3 app:

$ rails new contrived

And setting up its gems:

$ cd contrived
$ bundle install

And let’s add some scaffolding to keep track of our websites, serif fonts and sans serif fonts:

$ rails generate scaffold Website url:string
$ rails generate scaffold SerifFont name:string
$ rails generate scaffold SansSerifFont name:string

Now let’s hook up the root URL to point to the list of websites by adding this line to config/routes.rb:

  root :to => 'websites#index'

And remove the autogenerated index.html file:

$ rm public/index.html

Set up the database:

$ rake db:create
$ rake db:migrate

Now we are all set to fire up the app!

$ rails server

Navigating to http://localhost:3000 should show you something like this:

Step 2: Adding Tabs

Let’s use the ultrafantastically superb tabulous gem to add tabs to this app. Add the following to your app’s Gemfile:

gem 'tabulous'

And then

$ bundle install

Now type the following magical line:

$ rails generate tabs

which will create a file called app/tabs/tabulous.rb which comes included with wonderful explanatory comments, free of charge. Here’s what the file looks like without comments:

Tabulous.setup do |config|
 
  config.tabs do
    [
      #------------------------------------------------------------------------------------------------------------------------#
      #    TAB NAME                 |    DISPLAY TEXT          |    PATH                     |    VISIBLE?    |    ENABLED?    #
      #------------------------------------------------------------------------------------------------------------------------#
      [    :websites_tab            ,    'Websites'            ,    root_path                ,    true        ,    true        ],
      [    :websites_tab            ,    'Websites'            ,    websites_path            ,    true        ,    true        ],
      [    :serif_fonts_tab         ,    'Serif Fonts'         ,    serif_fonts_path         ,    true        ,    true        ],
      [    :sans_serif_fonts_tab    ,    'Sans Serif Fonts'    ,    sans_serif_fonts_path    ,    true        ,    true        ],
      #------------------------------------------------------------------------------------------------------------------------#
      #    TAB NAME                 |    DISPLAY TEXT          |    PATH                     |    VISIBLE?    |    ENABLED?    #
      #------------------------------------------------------------------------------------------------------------------------#
    ]
  end
 
  config.actions do
    [
      #----------------------------------------------------------------------------#
      #    CONTROLLER           |    ACTION          |    TAB                      #
      #----------------------------------------------------------------------------#
      [    :websites            ,    :all_actions    ,    :websites_tab            ],
      [    :websites            ,    :all_actions    ,    :websites_tab            ],
      [    :serif_fonts         ,    :all_actions    ,    :serif_fonts_tab         ],
      [    :sans_serif_fonts    ,    :all_actions    ,    :sans_serif_fonts_tab    ],
      #----------------------------------------------------------------------------#
      #    CONTROLLER           |    ACTION          |    TAB                      #
      #----------------------------------------------------------------------------#
    ]
  end
 
  config.active_tab_clickable = false
  config.always_render_subtabs = false
  config.raise_error_if_no_tab_found = true
  config.html5 = false
  config.css.scaffolding = true
  # config.css.background_color = '#ccc'
  # config.css.text_color = '#444'
  # config.css.active_tab_color = 'white'
  # config.css.hover_tab_color = '#ddd'
  # config.css.inactive_tab_color = '#aaa'
  # config.css.inactive_text_color = '#888'
 
end

You’ll notice that the file already has some tab data setup. Tabulous inspects your routes and tries to guess what tabs you may want, microsoft-clippy-style. Which means it gets it wrong. We really don’t need two websites tabs, so let’s delete one of them:

  config.tabs do
    [
      #------------------------------------------------------------------------------------------------------------------------#
      #    TAB NAME                 |    DISPLAY TEXT          |    PATH                     |    VISIBLE?    |    ENABLED?    #
      #------------------------------------------------------------------------------------------------------------------------#
      [    :websites_tab            ,    'Websites'            ,    websites_path            ,    true        ,    true        ],
      [    :serif_fonts_tab         ,    'Serif Fonts'         ,    serif_fonts_path         ,    true        ,    true        ],
      [    :sans_serif_fonts_tab    ,    'Sans Serif Fonts'    ,    sans_serif_fonts_path    ,    true        ,    true        ],
      #------------------------------------------------------------------------------------------------------------------------#
      #    TAB NAME                 |    DISPLAY TEXT          |    PATH                     |    VISIBLE?    |    ENABLED?    #
      #------------------------------------------------------------------------------------------------------------------------#
    ]
  end
 
  config.actions do
    [
      #----------------------------------------------------------------------------#
      #    CONTROLLER           |    ACTION          |    TAB                      #
      #----------------------------------------------------------------------------#
      [    :websites            ,    :all_actions    ,    :websites_tab            ],
      [    :serif_fonts         ,    :all_actions    ,    :serif_fonts_tab         ],
      [    :sans_serif_fonts    ,    :all_actions    ,    :sans_serif_fonts_tab    ],
      #----------------------------------------------------------------------------#
      #    CONTROLLER           |    ACTION          |    TAB                      #
      #----------------------------------------------------------------------------#
    ]
  end

Let’s look at these two tables in more detail. The first table is where you define your tabs. The order that you define them in is the order that they appear in the view. The columns contain Ruby expressions that are evaluated in the context of a Ruby view (which is why we can use route helpers). The second table is necessary so that when a controller action is called we know what tab should be selected. :all_actions is a shortcut; you can explicitly list actions out, one on each row.

The next thing we need to do is tell tabulous where in the view the tabs should be rendered. Tabulous gives us two view helpers: tabs and subtabs. Open up your app/views/layouts/application.html.erb file and add them like so:

<!DOCTYPE html>
<html>
<head>
  <title>Contrived</title>
  <%= stylesheet_link_tag :all %>
  <%= javascript_include_tag :defaults %>
  <%= csrf_meta_tag %>
</head>
<body>
 
<%= tabs %>
<%= subtabs %>
<%= yield %>
 
</body>
</html>

Restart your Rails server and reload http://localhost:3000 in your browser. You should see something like this:

And there you have it. Tabs in Rails! That wasn’t so hard, was it?

Notice that the tabs are styled for you. Tabulous adds CSS scaffolding to get you started but you should eventually turn off the scaffolding and use your own CSS. If you view the HTML source you can see the CSS that tabulous generated which can give you a head start.

Step 3: Adding Subtabs

What you really want is to have a fonts tab with two subtabs: serif and sans serif. To do that, change your app/tabs/tabulous.rb file to the following:

  config.tabs do
    [
      #---------------------------------------------------------------------------------------------------------------------#
      #    TAB NAME                    |    DISPLAY TEXT    |    PATH                     |    VISIBLE?    |    ENABLED?    #
      #---------------------------------------------------------------------------------------------------------------------#
      [    :websites_tab               ,    'Websites'      ,    websites_path            ,    true        ,    true        ],
      [    :fonts_tab                  ,    'Fonts'         ,    serif_fonts_path         ,    true        ,    true        ],
      [    :serif_fonts_subtab         ,    'Serif'         ,    serif_fonts_path         ,    true        ,    true        ],
      [    :sans_serif_fonts_subtab    ,    'Sans Serif'    ,    sans_serif_fonts_path    ,    true        ,    true        ],
      #---------------------------------------------------------------------------------------------------------------------#
      #    TAB NAME                    |    DISPLAY TEXT    |    PATH                     |    VISIBLE?    |    ENABLED?    #
      #---------------------------------------------------------------------------------------------------------------------#
    ]
  end
 
  config.actions do
    [
      #-------------------------------------------------------------------------------#
      #    CONTROLLER           |    ACTION          |    TAB                         #
      #-------------------------------------------------------------------------------#
      [    :websites            ,    :all_actions    ,    :websites_tab               ],
      [    :serif_fonts         ,    :all_actions    ,    :serif_fonts_subtab         ],
      [    :sans_serif_fonts    ,    :all_actions    ,    :sans_serif_fonts_subtab    ],
      #-------------------------------------------------------------------------------#
      #    CONTROLLER           |    ACTION          |    TAB                         #
      #-------------------------------------------------------------------------------#
    ]
  end

Notice how subtabs’ names must end in _subtab. Also notice how the subtabs immediately follow the tab that groups them. Finally, notice in the actions section how we hooked up the controllers to the subtabs. For example, when an action of the SerifFontsController is rendered, the :serif_fonts_subtab will be selected. Since tabulous knows that the :fonts_tab is its parent, the :fonts_tab will also appear selected.

After you edit the tabulous.rb file you may notice the tables are all out of alignment. To prettify the file:

$ rake tabs:format

Refresh your browser. When you click on the “Fonts” tab you should now see subtabs like this:

The markup that’s generated looks like this:

<div id="tabs">
  <ul>
    <li class="inactive enabled"><a href="/websites" class="tab">Websites</a></li>
    <li class="active enabled"><span class="tab">Fonts</span></li>
  </ul>
</div>
<div id="subtabs">
  <ul>
    <li class="active enabled"><span class="tab">Serif</span></li>
    <li class="inactive enabled"><a href="/sans_serif_fonts" class="tab">Sans Serif</a></li>
  </ul>
</div>

Step 4: Profit!

There are many other things that tabulous can do, such as support HTML5 and disabled tabs. The best place to learn about the full capabilities of tabulous is to read the comments in the app/tabs/tabulous.rb file after you generate it.

You can also watch my live demo of tabulous that I presented to the Boston Ruby Group. They asked some really good questions.

Happy tabbing!

You can skip to the end and leave a response. Pinging is currently not allowed.

51 Responses to “Tutorial for Adding Tabs to Rails Using Tabulous”

  1. Ramprasad says:

    Hi,

    I figured out my mistake. Since I am not calling from the layout, I just needed to call that once from each of the views :D. Sorry for the trouble. But just one more question. The tab that is clicked displays appropriate content, but the tab is not highlighted. Only the first tab by default remains highlighted at all times. Where should I change this? Thanks.

  2. techiferous says:

    Hi Ramprasad,

    Use the config.actions block in your app/tabulous/tabulous.rb file to tell tabulous which tab should be highlighted (active). Note that you are mapping controller actions (not views or routes) to which tab should be active.

  3. Ramprasad says:

    Hi,

    Awesome. Works great. Thanks for the help. :)

  4. Alex says:

    Hi,
    nice job.
    I have a question: I’d like to create a signout tab (with Devise), and I need to put a :method => ‘delete’ somewhere. Do you have any clue?
    Thanks

  5. techiferous says:

    Go to the Ruby table that’s a part of the config.tabs block. In the PATH column you can put any Ruby code that you could put into a view. So you can use a route helper here.

  6. Stef says:

    Is it possible to enclose all the tabs in a form? When switching tabs, save the selections in the session and display the content in other tabs according to the session’s contents.
    I am working on a fairly complex form, but I don’t want to use a wizard, a tabbed form would be best.

    Thanks!

  7. techiferous says:

    @Stef I’m not sure if enclosing all the tabs in a form would work because the form would always be in the markup, no matter which tab was selected. That would be okay if all of the tabs were part of this form, but if you had non-form tabs it would not be so good.

    Maybe you should have a separate form for each tab, if possible. I haven’t tried splitting up a form using tabulous yet, so I don’t have a good answer for you.

  8. Eric says:

    Hi,
    I tried your gem. it is fabulous. I follow your tutorial. I put my root_path as the first tab, but it is not clickable and no hyperlink. I notice “config.active_tab_clickable= false ” is default setting, but I click the other tab, first tab is still inactive.

  9. Eric says:

    Hi,

    Is there a way to display some tab in condition like user login or user is admin or not

    Thank

  10. techiferous says:

    Hi Eric,

    Yes, it is possible to display tabs conditionally. Any Rails code that can be executed in a Rails view can be put in the “visible?” column. You are not limited to true or false.

    Did you figure out your root_path issue? If not, feel free to post a link to a gist containing your config file and I can help you troubleshoot it.

  11. Eric says:

    Hi Techiferous,

    Thank you, I figure it out. the root_path issue.

    I see so I can your any other conditional method like “if “?

    I try to use autotest and rsepc to do the testing, but seem like tabulous is not compatibly with the autotest. I am getting some error
    activesupport-3.0.10/lib/active_support/dependencies.rb:488:in `load_missing_constant’: Expected /home/eric/workspace/tinimart/app/tabs/tabulous.r
    b to define Tabulous (LoadError)

    This is my Gemfile

    gem ‘rails’, ‘3.0.10’
    gem ‘sqlite3’
    gem ‘gravatar_image_tag’, ‘0.1.0’
    gem ‘will_paginate’, ‘3.0.pre’
    gem ‘nokogiri’

    group :development do
    gem ‘rspec-rails’, ‘2.0.0’
    gem ‘annotate’
    gem ‘faker’, ‘0.3.1’
    gem ‘tabulous’
    end

    group :test do
    gem ‘rspec’, ‘2.0.0’
    gem ‘spork’
    gem ‘webrat’, ‘0.7.1’
    gem ‘factory_girl_rails’, ‘1.0’
    end

  12. techiferous says:

    Eric,

    That’s a hard error to debug; the cause of the error is not always what you think it is: http://stackoverflow.com/questions/93853/how-to-fix-debug-expected-x-rb-to-define-x-rb-in-rails

    Feel free to open an issue on tabulous on github and I can try to resolve it when I have some time.

  13. shir says:

    Thanks! Amaizing.

  14. Felipe Cerda says:

    Hi,

    Is it possible to hide tabs on certain pages of the application? I think you said back in April that this is not possible, but I’m wondering if you added that functionality.

    Regards

  15. techiferous says:

    Felipe,

    Yes, that behavior is built in. If you have a view that you don’t want tabs in, make sure that the view (or its layout) does not call the tabs or subtabs helper methods. Also, that view’s action should not appear in the tabulous configuration file.

  16. Scott Shea says:

    As one of those poor fools cursed to code in Windows but deploy to Linux let me take a moment to thank you for making this bi-platformal (is that a word?). About 6 minutes after reading the tutorial I had my tabs up and running both locally and on the server I deploy to.

  17. Fabio says:

    Hi,
    How can display a subtab only for actions show and edit?
    Thanks
    Fabio

  18. techiferous says:

    Fabio,

    The “visible?” column doesn’t just take true/false values, it takes any Ruby expression that can be evaluated in the context of a view. So you can reference instance variables and helper methods there.

    For example, if you defined a @show variable in the show and edit actions, you can put (!@show.nil?) in the “visible?” column.

    There are other ways to do this, but I hope you get the gist.

    –Wyatt

  19. Khalid Naseem says:

    Tabulous is an amazing and simple gem. I have used tabs and subtabs sparingly in my web app for my company. Your instructions are easy to follow and straight forward. Hope you add more features for styling tabs.

    Regards,
    Khalid Naseem

  20. Teemu Leisti says:

    I’d just like to drop a note of appreciation for the Tabulous gem. It works well and integrates quite nicely with Bootstrap, which is just what I needed.

  21. techiferous says:

    Wow, thanks, Teemu!

  22. CrazeROR says:

    Hi..
    It was indeed very useful information. Thanks a lot..
    I have tried these total steps and its working fine.
    But, here comes the problem. Initially, i have used ‘devise’ gem for user authentication of my website. Again i liked to use this ‘tabulous’. I tried added these things. But since ‘devise’ has no session controller, it is showing error as ‘Tabulous::NoTabFoundError in Devise/sessions#new
    Tabulous Error: No tabs are defined for the controller ‘sessions’. You can define a tab for this controller in app/tabs/tabulous.rb in the ‘config.actions =’ section. You can also turn off NoTabFoundErrors by changing the value of config.when_action_has_no_tab.’

    Kindly help me with this issue. I really want to know about this. Thanks !!!

  23. techiferous says:

    @CrazeROR,

    Go into your app/tabs/tabulous.rb file and change the value of config.when_action_has_no_tab to :raise_error, :do_not_render, or :render depending on what you want to happen. If you want the error to go away when signing in and no tabs to show in that view, :do_not_render is the way to go.

    Hope this helps, and thanks for using tabulous!

  24. Miguel says:

    Hi,

    If i want to create tabs dynamically, for ex. if i have a link that when i press create a new tab, can i do this with this gem?

  25. techiferous says:

    Hi Miguel,

    No, tabulous does not support dynamic tab creation. However, depending on your needs, you might be able to layer some custom JavaScript on top of tabulous that would hide/show tabs as needed.

Leave a Reply