Fancygrid
Fancygrid mades it easy to create and render tables for database records in rails.
Features
- Ajax data fetch
- Pagination
- Simple search
- Complex search with 20 different conditions
- Column sorting
- View state caching
- ActiveRecord supported. MongoDB coming (some day).
- Column values from attributes, methods, method chains or even custom blocks
Requirements
- jQuery >= 1.4.2
- jQuery-ui (required if column sorting is wanted)
- Rails 3
- Haml
Installation
In your gemfile
gem 'fancygrid'
Run
bundle install
If you use Rails3 with asset pipeline enabled, you can just require the javascript and css
// = require fancygrid
If your asset pipeline is disabled, you have to copy the assets from the gems lib directory. There is no generator for this task.
Getting started
Basic Setup
In any controller in any action you can define a fancygrid for a specific model.
Here is an example for a simple table for the Users model:
def index
fancygrid_for :users do |g|
g.attributes :id, :username, :email
g.ajax_url = users_path
g.find
end
end
To render the fancygrid in the view, use the same name that you passed in the setup
# app/views/users/index.html.haml
= fancygrid :users
Changing default comparison operator
The default SQL string comparison operator is LIKE '%term%'
. You can update this to Postgresql's case-insensitive ILIKE
as seen below:
def index
fancygrid_for :users do |g|
g.search_operator = :insensitive_like
g.attributes :id, :email, :created_at
end
end
The LIKE options include :like
(the default), :starts_with
, :ends_with
, :insensitive_like
, :insensitive_starts_with
, and :insensitive_ends_with
.
Static tables
If you dont want to have an ajax table, dont specify the ajax_url. The data will be
queried and the table will be rendered without pagination.
def index
fancygrid_for :users do |g|
g.attributes :id, :username, :email
g.find
end
end
Table names and model names
Usually fancygrid tries to resolve the models class and table name from given
name. If you happen to use namespaced models, you must pass the class as an option.
def index
fancygrid_for :user, :class => Namespace::User do |g|
end
end
Optionally you can also pass a specific table name. However, if the class responds
to #table_name, this is not necessary.
def index
fancygrid_for :user, :class => Namespace::User, :table_name => "users" do |g|
end
end
Add class and id values to table and tr and td table elements
To add a class or id to either the table, TR, or TD elements you add it to the fancygrid_for block like this:
def index
fancygrid_for :user do |g|
g.tr_id do |record|
"row-#{record.id}"
end
g.tr_id = :row_id
g.table_class = "user_table"
end
Define columns
To display attributes as columns use the #attributes method for setup like this:
def index
fancygrid_for :users do |g|
g.attributes :id, :email, :created_at
end
end
For everything else use the #columns method. You can have method names,
method chains and procs to resolve column values.
def index
fancygrid_for :users do |g|
g.columns :full_name, :some_other_method
g.columns "orders.count"
g.columns :roles do |record|
record.roles.map(&:name).join(", ")
end
end
end
For more complex output you have to format the cell value in the view or a formatter method.
Columns formatting
Add a block to the fancygrid call in the view. In there you can use a switch condition
on the columns name to determine what to render. Do not forget to add the else case to
render all unformatted values.
= fancygrid :users do |column, record, value|
- case column.name
- when :actions
= link_to "Show", user_path(record)
= link_to "Edit", edit_user_path(record)
- else
/ this else case is important
= value
belongs_to or has_one associations
To define columns for associations, use the #columns_for method.
def index
fancygrid_for :users do |g|
g.columns_for :contact do |contact|
contact.attributes :first_name, :last_name
end
g.find do |query|
query.select :contact_id
query.includes :contact
end
end
end
Mention that in the query block the contact_id is selected. This is required, since fancygrid
tries to use optimized sql queries by default. Therefore it will select only those attributes
that have been used during the fancygrid setup. If the contact_id is missing, it will not be
possible to include the contact association.
If your association name is different from the models name, pass the model
class as option.
def index
fancygrid_for :users do |g|
g.columns_for :invoice_address, :class => Address do |adr|
adr.attributes :street, :zipcode, :city
end
end
end
has_many or has_and_belongs_to_many associations
If you have Users that has_many Orders, you should rather define a fancygrid
for the Orders than for Users. However, if it must be a Users table and
you want to search on the associations attributes, you can do that:
def index
fancygrid_for :users do |g|
g.columns_for :roles do |roles|
roles.attributes :name
end
end
end
The definition is valid, and you can already search for users with a specific
role. But nothing is going to be rendered in the roles.name column. This is
because roles is a collection of records, and not a single record. You can now
format the column in the view like this
= fancygrid :users do |column, record, value|
- case column.identifier
- when "roles.name"
= record.roles.map(&:name).join("|")
- else
= value
Here the column identifier is used to identify the column. This is useful
if you have more columns that are named the same.
Caching the view state
To make your users life easier you can enable the view state caching. This way
the user can search for data, leave the site, come back and have his last
search back on screen.
def index
fancygrid_for :users, :persist => true do |grid|
end
end
Copyright
Copyright (c) 2010 Alexander Graefenstein. See LICENSE for details.