Lugo Labs

Creating data backed tables with Tabular and Ruby on Rails

We have been building data tables for ages, and much of the elements are the same, such as fetching data from the server, presenting them on a table, being able to search, sort, etc.. Today we'll gather all these into a simple page using Tabular and Ruby on Rails for the server side. Rails is not really important here and we could have used any backend web framework.

Setup

Tabular needs jQuery so we make sure we have that included on our page. Then we grab the JavaScript file from Tabular's Github repo and save it on the /vendor/assets/javascripts folder of our Rails app, or whatever folder you put your JavaScript files if you don't use Rails.

We then grab the minimal Tabular CSS file and add it to the /vendor/assets/stylesheets folder (or your folder of choice). In Rails we need to reference the files into our application.js and application.css files respectively.

The Model

Since we're showing a table of users, we have a User model with the following attributes, that will be shown on the table.

  • id
  • name
  • email
  • company
  • salary

We have populated the users table with some fake data using the awsome ffaker gem. We've ended up with around 200 users, in order to see the pagination working.

The Controller

In a simple UsersController controller we have an index action that looks like this:

ruby
# app/controllers/users_controller

class UsersController < ApplicationController
  def index
    @page_size = (params[:page_size] || 10).to_i
    @users     = User.page(params[:page]).per(@page_size)
    if params[:sort].present?
      @users = @users.order(params[:sort][:name] => params[:sort][:dir])
    end
    if params[:q].present?
      @users = @users.where('LOWER(name) LIKE ?', "%#{params[:q]}%")
    end
  end
end

We have used the kaminari gem for pagination. Please note the parameters that work with Tabular:

  • page_size - provides the number of rows per page, by default one of 10, 25, 50; we can also specify our own variants
  • page - provides the number of the current page; it could be nil.
  • sort[:name] - the name of the column we're sorting by
  • sort[:dir] - the direction of sorting
  • q - the search term

As we can see, we have full control on pagination, sorting, and searching on the back end and we can apply them as we wish.

The Views

Tabular accepts the data in JSON format, so we build the index view with JBuilder:

ruby
# app/views/users/index.json.jbuilder

json.metadata do
  json.current_page  @users.current_page
  json.total_pages   @users.total_pages
  json.total_entries @users.total_count
  json.page_size     @page_size
end

json.data do
  json.array! @users
end

Tabular's data format is built of two parts:

  • metadata: Object - provides information about the data
  • data: Object[] Array - the actual data

The metadata includes information such as:

  • current_page - the number of the current page
  • total_pages - the total number of pages
  • total_entries - the total number of rows
  • page_size - the number of rows currently shown on a page, initially provided by Tabular

The data is provided as an array of User objects, created in a user partial:

ruby
json.extract! user, :id, :name, :email, :company

json.salary number_to_currency(user.salary)

json.show_link link_to('View', user_path(user), class: 'tabular-btn')

Here we extract the data we need from the User, including the salary formatted as currency. Tabular also accepts HTML markup, so we include a link to the user details. The tabular-btn class is provided by Tabular and we'll see the styles a bit later.

Setup

Not it's time to instantiate Tabular, and we'll do this on the app/views/users/index.html.erb page:

html
<h1>Users</h1>

<div id="tabular" class="tabular-demo"></div>

<script>
  $(function() {
    tabular.start('#tabular', {
      columns: [
        { title: 'Id', name: 'id' },
        { title: 'Name', name: 'name' },
        { title: 'Email', name: 'email' },
        { title: 'Company', name: 'company' },
        { title: 'Salary', name: 'salary' },
        { title: '', name: 'show_link', sort: false }
      ],
      source:      '/users.json'
    });
  });
</script>

Tabular can be instantiated by calling tabular.start function with the table container and some options (more info at Tabular page).

The columns options accept an array of object options for each table column:

  • title - the text to show on the headings
  • name - name of the data attribute in JSON response from the server
  • sort - tells Tabular to use sorting for this column.

The source specifies the link to server data.

Styles

Tabular is not opinionated about styles, it lets most of the bulk of it to us users, so that we can inject our own custom or framework styles, such as Bootstrap or Foundation. Tabular does come with a small CSS file that we already included on our page, outligning the basic layout of its plugin elements.

We're going to add our own styles though, taking advantage of the CSS classes assigned to different elements by Tabular.

css
.tabular-demo {
  .tabular-btn {
    background: #ceeffb;
    border: none;
    border-radius: 2px;
    font-size: .8em;
    color: #598da0;
    cursor: pointer;
    display: inline-block;
    padding: .2em .4em;

    &:hover {
      background: #a8dff3;
    }

    &[disabled] {
      color: #86daf6;
      cursor: default;

      &:hover {
        background: #ceeffb;
      }
    }
  }

  .tabular-paginator select {
    height: 1.8em;
  }

  .tabular-paginator-info {
    font-size: .8em;
  }

  .tabular-header {
    margin-bottom: 1em;
  }

  .tabular-search {
    float: right;

    input {
      font-size: .8em;
      padding: .2em .3em;
      border: 1px solid #ddd;
      border-radius: 2px;
    }
  }

  th,
  td {
    font-size: .8em;
    padding: .2em;
    border-bottom: 1px solid #eee;

    &:last-child {
      text-align: right;
    }
  }

  th {
    border-top: 2px solid #eee;
    border-bottom-width: 2px;

    a {
      text-transform: uppercase;
      font-size: .8em;
    }
  }

  .tabular-sort {
    padding-right: 1.5em;
  }
}

Here we style the buttons, the table headings and cells to achieve a layout as in the demo page. You may extend the styles as it fits the needs of your web app.

Conclusion

In the demo page you may see click on the headings to test how sorting works, check the pages dropdown, etc.. This is a small example on how to tabulate data on a web app, without reinventing the wheel about searching, sorting, pagination, loading data, etc..