Ext JS - Learning Center

Tutorial:Using Ext Grid with Ruby on Rails

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: This tutorial takes the reader step-by-step through an example that uses the Ext Grid component with a Ruby on Rails backend.
Author: Timothy Fisher
Published: April 25, 2007
Ext Version: 1.1
Languages: en.png English

Ruby on Rails is currently the hottest, and most hyped web development framework. The Rails framework includes tight integration with the Prototype and Scriptaculous JavaScript libraries. With the addition of Prototype and Scriptaculous as a backend choice for the Ext JavaScript library, the integration of Ext with Rails has become much easier to accomplish, with less overall included code. This tutorial will show you step-by-step all the steps that are necessary to use the Ext Grid component within a Rails web application. The tutorial uses JSON as the mechanism to send the grid data to the browser. Remote sorting of grid data is also included in the tutorial. The tutorial assumes basic familiarity with both Ext and Rails. All the necessary source code to recreate this tutorial grid is available for download, but it is up to the reader to understand how to setup a Rails project and to know where to place each of the files.

Contents

Let's Get Started

We will create a web page that displays a list of movies in a grid view. The movie grid that we create will be implemented using the Ext Grid component. The first thing we will do is create an application layout template that includes the necessary Ext JavaScript files. In our application.rhtml template file, we include the ext-all.css stylesheet, and the prototype.js, scriptaculous.js, effects.js, ext-prototype-adapter.js, and ext-all-debug.js JavaScript files. The home directory for all Ext files is assumed to be a subfolder named 'ext' in the public/javascripts directory of your Rails project. We use the appropriate Rails Helpers to include each of these files. The yield statement is where our main page content will be inserted.

Application Layout (application.rhtml)

<html>
    <head>
        <title>Movie Manager</title>
 
        <%= stylesheet_link_tag "../javascripts/ext/resources/css/ext-all.css" %>
        <%= javascript_include_tag "ext/adapter/prototype/prototype.js" %>
        <%= javascript_include_tag "ext/adapter/prototype/scriptaculous.js" %>
        <%= javascript_include_tag "ext/adapter/prototype/effects.js" %>
        <%= javascript_include_tag "ext/adapter/prototype/ext-prototype-adapter.js" %>
        <%= javascript_include_tag "ext/ext-all-debug.js" %>
 
    </head>	
    <body>	
        <%= yield %>		
    </body>
</html>

After we have our application template created, our next step is to create the view template for our movie list screen. In the view template, list.rhtml, we create a div element to hold the Ext Grid that will be rendered with JavaScript. We also include a JavaScript file called grid-paging.js. We will put our grid related JavaScript code into the grid-paging.js file. We give the grid div an id of 'movies_grid'. This id will be referenced later in our JavaScript code that we will use to initialize the grid with.

View Template (list.rhtml)

<%= javascript_include_tag "grid-paging.js" %>
<div id="movies_grid" style="border:5px solid #99bbe8; overflow:hidden; width:650px;"></div>

Setting Up the Grid - JavaScript

Next, we need some JavaScript code to initialize and render the Ext Grid. We create a file called grid-paging.js which will hold the JavaScript code that we write to initialize our webpage. By using the Ext.onReady function, our grid is initialized at page load time. In our initialization code, we first create an Ext.data.Store object to serve as a client-side data store for our movie data. In the Store object, we create an Ext.data.HttpProxy that holds the url the grid will access to get its data. We also specify a JsonReader as the mechanism for reading the data returned by the backend. We pass the schema of our JSON data to the JsonReader as we create it. Finally, by setting remoteSort to true, we are telling the Store that sorting of the data will be done on the server and each time a column header is clicked, a new data request should be made to the server.

After the Store object is created, we next create an Ext.grid.ColumnModel object to specify the layout of our grid columns. After specifying the layout of our columns, we set the defaultSortable property of the ColumnModel to true. This makes the columns sortable by clicking on the column headers.

Finally, we create the Ext.grid.Grid object, passing in the Store and ColumnModel objects created previously as initialization parameters. We also specify a single selection RowSelectionModel for our grid. We then render the grid, and call the load method on our Store object to perform the initial data load.

JavaScript Code (grid-paging.js)

var grid;
var ds;
 
Ext.onReady(function(){
	init_grid();   
});
 
function init_grid() {
    ds = new Ext.data.Store({
		proxy: new Ext.data.HttpProxy({url: '/movie/grid_data'}),
 
        reader: new Ext.data.JsonReader({
            root: 'Movies',
            totalProperty: 'Total',
            id: 'id'
        }, [
            {name: 'title', mapping: 'title'},
            {name: 'plot', mapping: 'plot'},
            {name: 'release_year', mapping: 'date'},
            {name: 'genre', mapping: 'genre'},
            {name: 'mpaa', mapping: 'mpaa'},
            {name: 'directed_by', mapping: 'directed_by'}
        ]),        
        // turn on remote sorting
        remoteSort: true	
    });
 
    var cm = new Ext.grid.ColumnModel
    	([{
           id: 'title',
           header: "Title",
           dataIndex: 'title',
           width: 250
        },{
           header: "Release Year",
           dataIndex: 'release_year',
           width: 75
        },{  
           header: "MPAA Rating",
           dataIndex: 'mpaa',
           width: 75
        },{  
           header: "Genre",
           dataIndex: 'genre',
           width: 100
        },{  
           header: "Director",
           dataIndex: 'directed_by',
           width: 150
        }]);
 
    cm.defaultSortable = true;
 
    grid = new Ext.grid.Grid('movies_grid', {
        ds: ds,
        cm: cm,
        selModel: new Ext.grid.RowSelectionModel({singleSelect:true}),
		autoExpandColumn: 'title'
    });
 
    grid.render();    
    ds.load({params:{start:0, limit:20}});	
}

Implementing the Server Side

Now we have the front-end code in place, but we have no backend code yet to actually get the movie data and perform the sorting. For the backend code, we now create a Rails controller class, MovieController. Remember, when we wrote the grid's initialization JavaScript, we used a url of '/movie/grid_data' as the data source. In a Rails application, this will route to a grid_data method of the MovieController class. The MovieController class uses a model class called Movie. A migration file for creating the database schema to support this model is included with the downloadable files for this tutorial. The MovieController class contains two methods, list, and grid_data. The list method is called when the page is requested. This method is empty which causes Rails to automatically render a template named list.rhtml, which we showed earlier in this tutorial.

The real work on the server side is done in the grid_data method. This method is called via an AJAX call from the Ext Grid component when it is initialized, when the data is re-sorted, or when a new page of the data is selected. The data is rendered as JSON text with no layout applied to it. JSON data is what is expected on the browser side by the Ext Grid component that we setup earlier in the tutorial.

When a column header is clicked on the grid, another AJAX request is made to the grid_data method to retrieve the data in the specified sort order. The Ext Grid component automatically passes the following four parameters: start, limit, sort, and dir. The 'start' parameter specifies the row index to begin at, the 'limit' parameter specifies the number of rows to retrieve, the 'sort' parameter specifies the column being sorted by, and the 'dir' parameter specifies the direction of the sort, equal to either 'ASC' for ascending sort, or 'DESC' for descending sort. In our implementation, we use the Rails Paginator object to implement the paging behaviour. After retrieving the data from the database, a Hash called return_data is created with two elements, :Total, and :Movies. These are the two elements that the Ext Grid is expecting to find in the returned JSON hash. The :Total element specifies the total number of records available, and the :Movies element contains an array of all the movie data.

Rails Controller Code (movie_controller.rb)

class MovieController < ApplicationController
 
    def list
    end	
 
    # Called from the list page to get the movie list data to populate the grid.
    def grid_data
        start = (params[:start] || 1).to_i      
        size = (params[:limit] || 20).to_i 
        sort_col = (params[:sort] || 'id')
        sort_dir = (params[:dir] || 'ASC')
 
        page = ((start/size).to_i)+1
 
        @movie_pages = Paginator.new(self, Movie.count, size, page)    
 
        @movies = Movie.find(:all, 
                             :select => "id, title, plot, date, genre, mpaa, directed_by", 
                             :limit=>@movie_pages.items_per_page,
                             :offset=>@movie_pages.current.offset, 
                             :order=>sort_col+' '+sort_dir)
 
        return_data = Hash.new()      
        return_data[:Total] = @movie_pages.item_count      
        return_data[:Movies] = @movies.collect{|u| {:id=>u.id, 
                                            :title=>u.title,
                                            :plot=>u.plot, 
                                            :date=>u.date, 
                                            :genre=>u.genre, 
                                            :mpaa=>u.mpaa, 
                                            :directed_by=>u.directed_by} }      
        render :text=>return_data.to_json, :layout=>false
    end
end

What's Next?

In this tutorial, we took a very basic approach to integrating the Ext Grid component with our Rails application. A more Rails-like approach may be to create a Rails Helper method that allows the user to create and initialize an Ext Grid component using Ruby code, instead of having to write as much JavaScript code. This is the approach that Rails takes for using Prototype and Scriptaculous core components. Perhaps in a follow-on tutorial, I will explore the creation of such a Rails Helper.

  • This page was last modified 21:25, 11 September 2007.
  • This page has been accessed 16,840 times.