A Ruby wrapper and Rails plugin for jqGrid.
jqGrid is a rich featured data grid built with the jQuery javascript library. www.trirand.com/jqgridwiki/doku.php
Gridify defines a simplified, more consistent API for jqGrid rather than directly emulate the jqGrid api and options in Ruby.
Gridify tries to respect the MVC (model-view-controller) architecture of your application. This is challenging because grid features span all three areas: it’s clearly part of the “view” as it mostly resides in the browser; columns in the table often directly map to columns in the model (database); and grid’s ajax requests are handled by controllers. Gridfy gives you some flexibility in managing grids within MVC.
$ script/plugin install git://github.com/linoj/gridify.git
Be sure to include all the javascripts and stylesheets in the +<head>+ section of your layouts which use the grid, for example
<%= stylesheet_link_tag 'application' %> <%= stylesheet_link_tag 'ui/start/jquery-ui-1.7.2.custom' %> <%= stylesheet_link_tag 'ui.jqgrid' %> <%= stylesheet_link_tag 'ui.multiselect' %> <%= javascript_include_tag 'jquery-1.3.2.min' %> <%= javascript_include_tag 'jquery-ui-1.7.2.custom.min' %> <%= javascript_include_tag 'grid.locale-en' %> <%= javascript_include_tag 'jquery.jqGrid' %> <%= javascript_include_tag 'ui.multiselect' %>
Note: When you download jqGrid, jQuery, and jqUI grab all the bits you’ll be using (or just package everything)
Lets say we have an ActiveRecord model “Note” which we want to display in a grid.
In app/models/note.rb,
class Note < ActiveRecord::Base gridify end
In the NotesController,
def index if request.xhr? records = Note.find_for_grid :grid, params render :xml => Note.grid.encode_records(records) else @grid = Note.grid end end
In the app/views/notes/index.html.erb,
<%= raw @grid %> <h1>Notes Grid<h1> <table id="notes_grid"></table> <div id="notes_grid_pager"></div>
In this example, gridify
creates a default grid named “grid” for the Notes model. In the controller, the #index html action supplies the +@grid+ object used by the view; the #index xml action responds to request params
with the encoded data. In the view, [email protected]_s+ generates the javascript code needed for the grid, which populates the table and pager div.
Here we add some options, including
-
use a grid named “mylist” (allowing multiple grids on a model)
-
limit to specific grid columns
-
ajax requests in json format (instead of xml)
-
enable user resizing the grid width and height
-
enable user arranging and resizing columns
-
enable the search toolbar (search fields atop each column when search button is toggled)
In app/models/note.rb,
class Note < ActiveRecord::Base gridify :mylist, :only => [:title, :body, :updated_at], :data_type => :json, :resizeable => true, :arranger => [:sortable, :hide_show], :search_toolbar => true end
In the NotesController is same as Example 1 except returns json instead of xml (all the search and sort params are handled by find_for_grid)
def index if request.xhr? records = Note.find_for_grid :mylist, params render :json => Note.grid.encode_records(records) else @grid = Note.grid :mylist end end
In the app/views/notes/index.html.erb is the same as Example 1, except uses “mylist” name
<%= raw @grid %> <h1>My Notes List<h1> <table id="notes_mylist"></table> <div id="notes_mylist_pager"></div>
Here we progressively enhance an html table into a grid. Grid is independent of the ActiveRecord model. No ajax requests.
In app/views/notes/index.html.erb,
<%= Grid.new( Note, :dom_id => "list", :table_to_grid => true ) %> <h1>Notes List</h1> <table id="list"> <tr> <th>Title</th> <th>Body</th> </tr> <tbody> <% for note in @notes %> <tr> <td><%=h note.title %></td> <td><%=h note.body %></td> </tr> <% end %> </tbody> </table> <div id="list_pager"></div>
NotesController#index is standard html response, for example,
def index @notes = Note.all end
In the more complex example we take more control of individual columns, including
-
initially hide the created_at column
-
the title column is not resizable
and allow record (row) editing, adding, and delete via RESTful requests
In app/models/note.rb,
class Note < ActiveRecord::Base gridify :editable => true, :pager => true, :edit_button => true, :add_button => true, :delete_button => true do |grid| grid.column :created_at, :hidden => true grid.column :title, :resizable => false end end
In the NotesController is same as Example 1, with other actions
def index if request.xhr? records = Note.find_for_grid :grid, params render :xml => Note.grid.encode_records(records) else @grid = Note.grid end end def create if request.xhr? note_params = Note.grid.member_params(params) @note = Note.new( note_params ) # must return nothing on success (until we setup a format for returning ok vs error) msg = "" unless @note.save @note.errors.entries.each do |error| msg << "<strong>#{error[0]}</strong> : #{error[1]}<br/>" end end render :text => msg else @note = Note.new(params[:note]) if @note.save flash[:notice] = "Successfully created note." redirect_to @note else render :action => 'new' end end end def update @note = Note.find(params[:id]) if request.xhr? note_params = Note.grid.member_params(params) msg = "success" unless @note.update_attributes( note_params ) @note.errors.entries.each do |error| msg << "<strong>#{error[0]}</strong> : #{error[1]}<br/>" end end render :text => msg else if @note.update_attributes(params[:note]) flash[:notice] = "Successfully updated note." redirect_to @note else render :action => 'edit' end end end def destroy # NOTE: if allow multiselect should check :id for string of comma delimited id's @note = Note.find(params[:id]) @note.destroy if request.xhr? render :nothing => true else flash[:notice] = "Successfully destroyed note." redirect_to notes_url end end
In the app/views/notes/index.html.erb is the same as Example 1
<%= raw @grid %> <h1>Notes Grid<h1> <table id="notes_grid"></table> <div id="notes_grid_pager"></div>
For this to work, you should use my fork of jqgrid github.com/linoj/jqGrid which adds support for RESTful routes (see www.vaporbase.com/postings/jqGrid_for_RESTful_Rails ) until it gets merged.
The #member_params method maps the attribute parameters into a hash as expected by update_attributes.
By way of better practices, I recommend you ensure the grid javascript is placed in the document header. For example,
In views/layouts/application.rb, the +<header>+ should include
<header> ... <%= yield :head %> </header>
And in the views, say,
<% content_for :head %> <%= @grid %> <% end <h1>Notes Grid<h1> <table id="notes_grid"></table> <div id="notes_grid_pager"></div>
If it bothers you to put view-specific options in the model, these can be added later (e.g. in the view or in a view helper) using #update. For example,
<%= @grid.update( :search_toolbar => false ) %>
See the source code for all the options. For most of the grid and view options, see grid_options.rb. For column model options, see grid_column.rb.
You can escape the Gridify api and use the jqGrid native options directly.
Copyright © 2010 Jonathan Linowes, released under the MIT license