1. Handling a fetch request from RestDataSource using Ruby on Rails

Description

This sample shows how to integrate a SmartClient front-end with Ruby on Rails (also known as RoR or just "Rails").

The content discussed here will explore a way to integrate RoR with SmartClient, by leveraging SmartClient javascript API's on the front-end and MVC architecture in RoR web application on the back-end to generate the result sets. In this sample, a DataSource will be created which inherits from RestDataSource. This will get the data from the database using an RoR Model and will serialize it back to the DataSource in JSON format. The results will be displayed in a ListGrid.

Prerequisites

  • Ruby on Rails framework, at least version 3.x (requires Ruby 1.8.6 or higher). It can be downloaded for free from here.
  • MySQL Server has been used as the database.
  • SmartClient SDK, at least version 8.3p. This can be downloaded from here.  Any edition is OK, including the free LGPL version.

Setting up the application

Once you installed Rails on your development computer, first create the new Rails project with the command as follows:

rails new app1

After the new project has created, unzip your SmartClient SDK and copy the complete "isomorphic" folder from *smartclientRuntime\isomorphic to the public directory in your application's folder.

Next open the Gemfile in the project directory and add the 'smartclient' gem.

Gemfile
gem 'smartclient'
gem 'mysql2'

Smartclient gem

This gem will provide utility classes for working with SmartClient, such as a DSResponse class which represents the results of a DataSource operation. You can download this gem from here.

Then run the bundle command on the console:

bundle install

Configuring a Database 

The database to use is specified in a configuration file, config/database.yml. If you open this file in a new Rails application, you’ll see a default database configured to use SQLite3. The file contains sections for three different environments in which Rails can run by default:

  • The development environment is used on your development/local computer as you interact manually with the application.
  • The test environment is used when running automated tests.
  • The production environment is used when you deploy your application for the world to use.

 

If you choose to use MySQL database, your config/database.yml will look a little different. Here’s the development section:

 

development:
  adapter: mysql2
  encoding: utf8
  database: smartclient_development
  pool: 5
  username: root
  password:
  socket: /tmp/mysql.sock

 

If your development computer’s MySQL installation includes a root user with an empty password, this configuration should work for you. Otherwise, change the username and password in the development section as appropriate.

Creating database and sample SQL table

Now that you have your database configured, it’s time to have Rails create an empty database for you. You can do this by running a rake command:

rake db:create

And you need to define the schema.rb and create the table.

schema.rb
ActiveRecord::Schema.define(:version => 20130508132151) do
  create_table "supplyitems", :force => true, :primary_key => :itemID do |t|      
      t.string    :itemName
      t.string    :SKU
      t.string    :description
      t.string    :category
      t.string    :units
      t.float     :unitCost
      t.boolean   :inStock
      t.datetime  :nextShipment 
   end 
end

Once you defined the table structure, you can run the rake command and then the new table will be created on the mysql database.

rake db:schema:load

Generate sample data

In order to display the data on the ListGrid, the table that just was created should have sample rows.

You can do it by running a rake command, before you run the command, you need to define the seeds.rb in the db directory of the application.

seeds.rb
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
for count in 1..20
  itemID = count
  itemName = "Pens stabiliner " + count.to_s
  SKU = Random.rand(1000...9999)
  category = "Office paper Product"
  units = "Ea"
  unitCost = Random.rand(0.1...2)
  inStock = 1
  nextShipment = Time.now
  
  Supplyitem.create(:itemID => itemID,
                  :itemName => itemName, 
                  :SKU => SKU, 
                  :description => "Description" + itemID.to_s, 
                  :category => category, 
                  :units => units,
                  :unitCost => unitCost,
                  :inStock => inStock,
                  :nextShipment => nextShipment )
 
end

And you can run the command as follows;

rake db:seed

Finally you can start implementing with smartclient.

Creating the Model

rails g model supplyitem
app/model/supplyitem.rb
class Supplyitem < ActiveRecord::Base
  attr_accessible :itemID, :itemName, :SKU, :description, :category, :units, :unitCost, :inStock, :nextShipment
end

Adding SmartClient library path to the layout view

When Rails renders a view as a response, it does so by combining the view with the current layout.

We need to add the SmartClient library path to the layout page.

/app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Smartclient</title>
    
  <%= stylesheet_link_tag    "application", :media => "all" %>
  <script>var isomorphicDir = "./isomorphic/";</script>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>

/app/assets/javascripts/application.js
//= require ./isomorphic/system/modules/ISC_Core
//= require ./isomorphic/system/modules/ISC_Foundation
//= require ./isomorphic/system/modules/ISC_Containers
//= require ./isomorphic/system/modules/ISC_Grids
//= require ./isomorphic/system/modules/ISC_Forms
//= require ./isomorphic/system/modules/ISC_DataBinding
//= require ./isomorphic/skins/TreeFrog/load_skin

Adding these script tags will now ensure the master page will manage the loading of SmartClient, providing that this page is always defined as the master page for the view.

Creating the DataSource and Rails controller for data requests

We can use the rails command to create the new controller.

rails g controller smartclient

Open the created view for the application (in the Solution Explorer, in the app/views/smartclient folder, open Index.html.erb) and change it's content to:

index.html.erb
<SCRIPT>
isc.RestDataSource.create({
    "ID": "suppyItem",
    "fields":[
        {"name":"itemID", "type":"sequence", "hidden":"true", "primaryKey":"true"},
        {"name":"itemName", "type":"text", "title":"Item", "length":"128", "required":"true"},
        {"name":"SKU", "type":"text", "title":"SKU", "length":"10", "required":"true"},
        {"name":"description", "type":"text", "title":"Description", "length":"2000"},
        {"name":"category", "type":"text", "title":"Category", "length":"128", "required":"true" },
        {"name":"units", "type":"enum", "title":"Units", "length":"5",
            "valueMap":["Roll", "Ea", "Pkt", "Set", "Tube", "Pad", "Ream", "Tin", "Bag", "Ctn", "Box"]
        },
        {"name":"unitCost", "type":"float", "title":"Unit Cost", "required":"true",
            "validators":[
                {"type":"floatRange", "min":"0", "errorMessage":"Please enter a valid (positive) cost"},
                {"type":"floatPrecision", "precision":"2", "errorMessage":"The maximum allowed precision is 2"}
            ]
        },
 
        {"name":"inStock", "type":"boolean", "title":"In Stock"},
        {"name":"nextShipment", "type":"date", "title":"Next Shipment"}
    ],
 
    "dataFormat":"json",
    "dataURL":"/smartclient/data" 
});
isc.ListGrid.create({
    ID: "suppyItem",
    width: 700, height: 224, alternateRecordStyles: true,
    dataSource: suppyItem,
    autoFetchData: true
}); 
</SCRIPT>

Create a datasource which inherits RestDataSource and define the data URL to a controller. This controller will handle the requests from the DataSource. The fields in the newly created DataSource will match the columns in the database table created earlier.

Note, The required format  is 'json' and the data url is set to 'smartclient/fetch', which means the controller name will need to be set to 'SmartclientController' and the method name will be 'fetch'. As everything else is unchanged, the DataSource will send the request parameters in the URL of the request.

Now, create the controller to send back the response.

/app/controllers/smartclient_controller.rb
require 'DSResponse'
class SmartclientController < ApplicationController         
    def index
      
    end
    
    def data
      # get all supplyitems from the database
      @supplyItems = Supplyitem.find(:all)
      # get the count of the supplyitems
      supplyitems_count =  Supplyitem.count
      response = DSResponse.new
      response.data = @supplyItems
      response.startRow = 0
      response.endRow = supplyitems_count - 1
      response.status = 0
      response.totalRow = supplyitems_count      
            
      @result = { :response => response }
      
      render json: @result
    end
end 


The Rails router recognizes URLs and dispatches them to a controller’s action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views.

So after you created the new controller,  you should define the routes.rb

/config/routes.rb
Smartclient::Application.routes.draw do  
  root to: 'smartclient#index'
  get 'smartclient/data'  
end

 

By running rails server command, the application will start and a grid fetching and displaying the rows found in the table will be shown. (http://localhost:3000)

rails s

The complete code for this sample project can be downloaded from github.