= Gridify A Ruby wrapper and Rails plugin for jqGrid. jqGrid is a rich featured data grid built with the jQuery javascript library. http://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. == Installation $ script/plugin install git://github.com/linoj/gridify.git == Scripts 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) == Examples === Example 1 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, <%= @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, +@grid.to_s+ generates the javascript code needed for the grid, which populates the table and pager div. === Example 2 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 <%= @grid %> <h1>My Notes List<h1> <table id="notes_mylist"></table> <div id="notes_mylist_pager"></div> === Example 3 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 === Example 4 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 <%= @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 http://github.com/linoj/jqGrid which adds support for RESTful routes (see http://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. === Example 5 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 ) %> == API 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 (c) 2010 Jonathan Linowes, released under the MIT license