Skip to content
Simple creation of listings in rails applications
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib Tag version 0.1.10 Apr 2, 2018
script initial commit v0.0.1 Jun 13, 2013
.gitignore migrate dummy app to use rspec Jun 10, 2015
.ruby-gemset Added ruby-gemset file Jul 4, 2014
Gemfile initial commit v0.0.1 Jun 13, 2013
LICENSE initial documentation Jun 18, 2015 allow custom filter partial. for custom filter and data source based … Jul 1, 2015
Rakefile fix build: edge rails & db setup Jun 10, 2015
listings.gemspec Fix specs to run on rails 5.0.2 May 9, 2017


By Manas

Build Status

Listings aims to simplify the creations of listings for Rails 3 & 4 apps.

The listings created support when approriate sorting, pagination, scoping, searching, filtering and exports to csv or xls.

A listing data source have built in support for ActiveRecord and Arrays.


Add listings to your Gemfile:

gem 'listings'


Mount listings engine to in you config/routes.rb

Rails.application.routes.draw do
  mount Listings::Engine => "/listings"

Require assets in your Javascript and Stylesheet

//= require listings
 *= require listings

Create config/initializers/listings.rb file to make general configurations. Listings plays nice with twitter bootstrap 2 & 3 without explicitly including it.

# file: config/initializers/listings.rb
Listings.configure do |config|
  config.theme = 'twitter-bootstrap-3' # defaults to 'twitter-bootstrap-2'
  config.push_url = true # User html5 history push_state to allow back/forward navigation. defaults to false


Create listings files app/listings/{{name}}_listing.rb. See listings samples and the DSL

Use render_listing helper to include the listing by its name.

# file: app/listings/tracks_listing.rb
class TracksListing < Listings::Base
= render_listing :tracks


For a Track/Album model:

class Track < ActiveRecord::Base
  belongs_to :album
  attr_accessible :order, :title

  scope :favorites, -> { ... }

class Album < ActiveRecord::Base
  attr_accessible :name
  has_many :tracks

a listing with

class TracksListing < Listings::Base
  model Track

  scope :all
  scope :favorites

  filter album: :name

  column :order
  column :title, searchable: true
  column album: :name, searchable: true

Listings DSL

A listing inherits from Listings::Base and defines de following DSL


model can be used with just an ActiveRecord class

  model Track

or with a block to perform further operations

  model do

or generate an array of objects or hashes

  model do
      {title: "Tishomingo Blues", album: {name: "The Royal J's" }},
      {title: "Save me for later", album: {name: "Me 'n' Mabel" }}


Declaring a column with a symbol renders that attribute

  column :title

column accepts options. By default { searchable: false, sortable: true }

Adding searchable: true will make a search box appear and perform a search depending on the datasource logic (field LIKE '%pattern%' for ActiveRecord datasource or include? for Object datasource)

  column :title, searchable: true

column can traverse object path and belongs_to relations

  column album: :name


  column [:album, :name]

column also accepts a block to alter the rendering of the field

  column album: :name do |track, album_name|

The block is evaluated in a view_context so any helper you will usually use in a view it can be used in the block

  column do |track|
    link_to 'Edit', edit_track_path(track)

  column do |track|
    # renders app/views/shared/_tracks_actions view
    render partial: 'shared/track_actions', locals: {track: track}

column also accepts a title: option

  column album: :name, title: 'Album'


Declaring a scope with a symbol with allow user to show only records matching the scope in the ActiveRecord class

  scope :favorites

You can change the displayed name but yet, using the declared scope

  scope 'My favorites', :favorites

If you don't want to pollute the model with scopes, or you need to filter items with a custome logic use a block

  scope 'My favorites', :favorites, lambda { |items| items.where(...) }


Declaring a filter will display a unique list of values of the field and allow the user to filter on exact match

  filter album: :name

It supports title: and a block

  filter album: :name, title: 'Album' do |album_name|

Also render: option can be used to suppress the rendering of the filter, but allowing the user to filter by it. For example to filter by the id:

  filter :id, render: false

Or render: can be user to indicate the partial to be used for rendering that filter. Hence allowing custom UI for certain filter among the default UI. See Templates for information regarding where the partial will be looked.

  filter :update_at, render: 'date'

Filters are rendered by default by the side of the listing. With layout method you can change this and render them on the top.

  layout filters: :top

Custom filters allows definition of custom meaning to a key. This filters are not rendered by default. Use render: option to indicate the partial to be used for rendering.

  custom_filter :order_lte do |items, value|
    items.where('"order" <= ?', value.to_i)


Page size can be specified by paginates_per

  paginates_per 40

And you can disable pagination

  paginates_per :none


Declare which formats you want to be available for export. Notice that paging will be ignored for the export.

  export :csv, :xls

Sometimes the columns should be rendered different for the export a format property is available and will be :html, :csv or :xls.

  column :email do |user, email|
    if format == :html
      mail_to email


css_class ca specify a css class to be apply to the listing

  css_class 'my-custom-style'

row_style can specigy a css class to apply to each row depending on the item it is rendering

  row_style do |track|
    'favorite-track' if track.favorite?

A column also support a class option to specify a css class to be applied on every table cell

  column :title, class: 'title-style'


Include listings/rspec in your spec_helper.rb

# file: spec/spec_helper.rb
require 'listings/rspec'

Ensure listing is able to render

# file: spec/listings/tracks_listing_spec.rb
require 'spec_helper'

RSpec.describe TracksListing, type: :listing do
  let(:listing) { query_listing :tracks }

  it 'should get tracks' do
    # ... data setup ...
    items = listing.items.to_a
    # ... assert expected items ...


Although titles can be specified in the listing definition, i18n support is available. Add to your locales:

    no_data: "No se encontraron %{kind}"
    export: "Descargar"
    search_placeholder: "Buscar %{kind}"
    records: "registros"
        title: 'Título'
        album_name: 'Nombre del Album'

Javascript api

The listing content can be reloaded preserving current sort, scope, search, filter and page.

To reload the listings rendered by

= render_listing :tracks



Change filters

$('#tracks.listings').trigger("listings:filter:key:clear", 'album_name')
$('#tracks.listings').trigger("listings:filter:key:set", ['album_name', 'Best of'])

View Helpers

Use render_listing helper to include the listing by its name.

= render_listing :tracks

Use listings_link_to_filter helper to render a link that will set a filter. Used to example when you want the user to be able to click on a cell value to filter upon that.

  column artist: :name do |album, value|
    listings_link_to_filter(value, :artist_id, album.artist_id)


There are a number of templates involved in rendering the listing. These templates can be rendered by the hosting app per listing or theme basis.

For example if a listing named tracks is rendered with twitter-bootstrap-3 theme the templates are looked up in the following locations/order:

  • <app>/views/listings/tracks/<partial>
  • <gem>/views/listings/tracks/<partial>
  • <app>/views/listings/twitter-bootstrap-3/<partial>
  • <gem>/views/listings/twitter-bootstrap-3/<partial>
  • <app>/views/listings/<partial>
  • <gem>/views/listings/<partial>

This lookup logic is inside Listings::ActionViewExtensions#listings_partial_render.

Under the hood

The first listing is rendered in the context of the request, so the first page will be displayed with no delay.

Any further interaction with the listing will end up in a AJAX call attended by the mountable engine.


listings is Copyright © 2003 Manas Technology Solutions. It is free software, and may be redistributed under the terms specified in the LICENSE file.

You can’t perform that action at this time.