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.
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.
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.
# 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
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.
<!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>
//= 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:
<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.
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
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.