Shield UI jQuery Grid Integration with Ruby on Rails
The Shield UI JavaScript framework allows for an easy and straightforward integration with various RESTful frameworks. In this article we will demonstrate how the Shield UI jQuery Grid Component can be integrated with a standard Ruby on Rails application. The integration takes about 30 minutes to complete from scratch and the complete project is available on GitHub.
Project Setup
Let’s start with setting up a new Rails project assuming the latest Ruby version is installed in RVM and the environment is properly configured as described in the documentation. First we need to create a directory that will contain our new Rails application and install the latest Rails framework and the Bundler gem for managing the application packages:
$ mkdir shieldui-grid-rails $ echo '2.3.1' > shieldui-grid-rails/.ruby-version $ echo 'shieldui-grid' > shieldui-grid-rails/.ruby-gemset $ cd shieldui-grid-rails $ gem install bundler rails
Once all the dependencies are installed we have to initialize the application:
$ rails new .
This will create the application structure in the current directory and add all necessary files. To test that the application setup is successful let's create the database and start the server.
$ rake db:create $ rails server
If everything is properly configured we should have a working Ruby on Rails application that renders the built-in welcome page in the browser:
To facilitate the application views rendering we will add the Twitter Bootstrap responsive layout framework by following the installation instructions for the bootstrap-sass gem.
Finally we will generate a new scaffold that will create all Rails components and expose the RESTful routes that the Shield UI Grid will use to handle the data. The scaffold in our case will represent the expenses for a personal finance tracking application:
$ rails generate scaffold expense date:date title:string amount:decimal $ rake db:migrate db:test:prepare
Shield UI Components Setup
We are going to use the Shield UI Lite version licensed under the MIT license as described in the GitHub repository. First we will install the framework in vendor/shieldui-lite following the instructions:
$ mkdir vendor/shieldui-lite $ git clone git@github.com:shieldui/shieldui-lite.git vendor/shieldui-lite $ cd vendor/shieldui-lite $ npm install $ grunt build
After the build has finished we need to copy the files from the dist/ folder and some of the external dependencies to vendor/assets/ and include them in the application JavaScript manifest and the application SCSS files:
$ cp dist/js/shieldui-lite-all.min.js ../assets/javascripts/shieldui-lite-all.min.js $ cp -r external/{globalize,sinon} ../assets/javascripts/
# app/assets/javascripts/application.js //= require jquery //= require bootstrap-sprockets //= require jquery_ujs //= require turbolinks //= require globalize/globalize //= require sinon/sinon //= require shieldui-lite-all.min //= require_tree .
As an alternative we can use the Shield UI Components trial version in our new Rails application by skipping the lite version setup and simply including a JavaScript include tag in the app/views/layouts/application.html.erb layout file
# app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>Grid</title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag '//shieldui.com/shared/components/latest/js/shieldui-all.min.js', 'data-turbolinks-track': 'reload' %> </head> <body> <div class=“container”> <%= yield %> </div> </body> </html>
For styling the jQuery Grid and the rest of the Shield UI components we need to add the CSS dependencies in the app/assets/stylesheets/application.scss SCSS file:
# app/assets/stylesheets/application.scss @import '//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.0/normalize.min.css'; @import '//shieldui.com/shared/components/latest/css/shieldui-all.min.css'; @import '//shieldui.com/shared/components/latest/css/light/all.min.css'; @import 'bootstrap-sprockets'; @import 'bootstrap';
Preparing the application
After the Shield UI Components are setup let’s create a new dashboard controller and a default action for rendering the Grid that will use the expenses controller RESTful actions for managing the expenses data:
$ rails generate controller dashboard default
We will use the newly created default dashboard controller action as the default route:
# config/routes.rb Rails.application.routes.draw do root to: 'dashboard#default' resources :expenses end
The last step for integrating the Shield UI Grid Component is to add a placeholder <div id="expenses"></> for the data to the the default dashboard view:
# app/views/dashboard/default.html.erbExpenses
Seeding the database
Testing the Grid widget integration in our Rails application will require some sample data. We can add some expense records using the database seed helper and to do that we will add the Faker gem to our Gemfile and update the seeds file:
$ echo "gem 'faker'" >> Gemfile $ bundle install
# db/seeds.rb Array.new(20) do Expense.create(title: Faker::Lorem.sentence, date: Faker::Date.between(1.week.ago, Date.today), amount: Faker::Number.decimal(2)) end
We can now easily populate the application database with 20 new expense records that can be used for testing:
$ rake db:seed
Integrating the Shield UI Grid Component
Once we have the sample data added to the application database we can proceed with the Grid integration. In the next sections we will implement the CRUD actions using the expenses controller RESTful actions.
Read
Reading the expenses data and rendering it in the Grid Component is as easy as specifying the DataSource remote option and pointing it to the expenses controller index action. We will also have to define the DataSource schema that maps each of the exposed expense attributes and the formatting option for each column:
# app/assets/javascripts/dashboard.coffee $ -> $('#expenses').shieldGrid dataSource: schema: fields: id: { path: 'id', type: Number } date: { path: ‘date’, type: Date } title: { path: 'title', type: String } amount: { path: 'amount', type: Number } remote: read: '/expenses.json' columns: [ { field: 'date', title: 'Date', width: 100, format: "{0:MM/dd/yyyy}" }, { field: 'title', title: 'Title', width: 200 }, { field: 'amount', title: 'Amount', width: 80 } ]
If we want to add pagination and sorting to our results we just need to specify the paging: true and sorting: true options:
# app/assets/javascripts/dashboard.coffee $ -> $('#expenses').shieldGrid dataSource: schema: fields: id: { path: 'id', type: Number } date: { path: 'date', type: Date } title: { path: 'title', type: String } amount: { path: 'amount', type: Number } remote: read: '/expenses.json' paging: true sorting: true columns: [ { field: 'date', title: 'Date', width: 100, format: "{0:MM/dd/yyyy}" }, { field: 'title', title: 'Title', width: 200 }, { field: 'amount', title: 'Amount', width: 80 } ]
Having done that the Shiled UI Grid will automatically load and render the expenses from the database when we open the application in the browser:
Update
Editing the jQuery Grid rows is available as a built-in action so we will first add a new Actions column that will render the edit button and enable the row editing option:
# app/assets/javascripts/dashboard.coffee $ -> $('#expenses').shieldGrid dataSource: schema: fields: id: { path: 'id', type: Number } date: { path: 'date', type: Date } title: { path: 'title', type: String } amount: { path: 'amount', type: Number } remote: read: '/expenses.json' paging: true sorting: true columns: [ { field: 'date', title: 'Date', width: 100, format: "{0:MM/dd/yyyy}" }, { field: 'title', title: 'Title', width: 200 }, { field: 'amount', title: 'Amount', width: 80 }, { title: 'Actions', width: 70, buttons: [ { cls: 'editButton', commandName: 'edit', caption: 'Edit' } ] } ] editing: enabled: true type: 'row'
Saving the data from the Grid is easily configured by adding a modify section to the DataSource options that defines an update callback which will trigger the AJAX request to the REST controller:
# app/assets/javascripts/dashboard.coffee $ -> $('#expenses').shieldGrid dataSource: schema: fields: id: { path: 'id', type: Number } date: { path: 'date', type: Date } title: { path: 'title', type: String } amount: { path: 'amount', type: Number } remote: read: '/expenses.json' modify: update: (items, success, error) -> newItem = items[0] $.ajax url: "/expenses/#{newItem.data.id}" type: 'PUT' dataType: 'json' data: { expense: newItem.data } .then(success, error) paging: true sorting: true columns: [ { field: 'date', title: 'Date', width: 100, format: "{0:MM/dd/yyyy}" }, { field: 'title', title: 'Title', width: 200 }, { field: 'amount', title: 'Amount', width: 80 }, { title: 'Actions', width: 70, buttons: [ { cls: 'editButton', commandName: 'edit', caption: 'Edit' } ] } ] editing: enabled: true type: 'row'
Create
The Shield UI jQuery Grid allows to easily implement creation of new entries that get automatically added to the grid. To implement the create functionality we just need to define the create callback in the DataSource modify options section and add a toolbar button for triggering the new row action:
# app/assets/javascripts/dashboard.coffeee $ -> $('#expenses').shieldGrid dataSource: schema: fields: id: { path: 'id', type: Number } date: { path: 'date', type: Date } title: { path: 'title', type: String } amount: { path: 'amount', type: Number } remote: read: '/expenses.json' modify: create: (items, success, error) -> newItem = items[0] $.ajax url: '/expenses' type: 'POST' dataType: 'json' data: { expense: newItem.data } complete: (xhr) -> if xhr.readyState == 4 and xhr.status == 201 newItem.data.id = xhr.responseJSON.id return success() error() update: (items, success, error) -> newItem = items[0] $.ajax url: "/expenses/#{newItem.data.id}" type: 'PUT' dataType: 'json' data: { expense: newItem.data } .then(success, error) paging: true sorting: true columns: [ { field: 'date', title: 'Date', width: 100, format: "{0:MM/dd/yyyy}" }, { field: 'title', title: 'Title', width: 200 }, { field: 'amount', title: 'Amount', width: 80 }, { title: 'Actions', width: 70, buttons: [ { cls: 'editButton', commandName: 'edit', caption: 'Edit' } ] } ] editing: enabled: true type: 'row' toolbar: [ { buttons: [ commandName: 'insert' caption: 'Add Expense' ] position: 'top' } ]
Delete
Deleting items is implemented by adding a delete button to the Actions column that will be used to remove each row. Sending the delete request to the controller is again handled by the DataSource modify section where we just need to add a remove callback:
# app/assets/javascripts/dashboard.coffeee $ -> $('#expenses').shieldGrid dataSource: schema: fields: id: { path: 'id', type: Number } date: { path: 'date', type: Date } title: { path: 'title', type: String } amount: { path: 'amount', type: Number } remote: read: '/expenses.json' modify: create: (items, success, error) -> newItem = items[0] $.ajax url: '/expenses' type: 'POST' dataType: 'json' data: { expense: newItem.data } complete: (xhr) -> if xhr.readyState == 4 and xhr.status == 201 newItem.data.id = xhr.responseJSON.id return success() error() update: (items, success, error) -> newItem = items[0] $.ajax url: "/expenses/#{newItem.data.id}" type: 'PUT' dataType: 'json' data: { expense: newItem.data } .then(success, error) remove: (items, success, error) -> newItem = items[0] $.ajax url: "/expenses/#{newItem.data.id}" type: 'DELETE' dataType: 'json' .then(success, error) paging: true sorting: true columns: [ { field: 'date', title: 'Date', width: 100, format: "{0:MM/dd/yyyy}" }, { field: 'title', title: 'Title', width: 200 }, { field: 'amount', title: 'Amount', width: 80 }, { title: 'Actions', width: 70, buttons: [ { cls: 'editButton', commandName: 'edit', caption: 'Edit' } { cls: 'deleteButton', commandName: 'delete', caption: 'Delete' } ] } ] editing: enabled: true type: 'row' toolbar: [ { buttons: [ commandName: 'insert' caption: 'Add Expense' ] position: 'top' } ]
To avoid accidentally deleting items we can easily setup a confirmation message for the delete action by adding a confirmation option to the editing options:
# app/assets/javascripts/dashboard.coffeee $ -> $('#expenses').shieldGrid dataSource: schema: fields: id: { path: 'id', type: Number } date: { path: 'date', type: Date } title: { path: 'title', type: String } amount: { path: 'amount', type: Number } remote: read: '/expenses.json' modify: create: (items, success, error) -> newItem = items[0] $.ajax url: '/expenses' type: 'POST' dataType: 'json' data: { expense: newItem.data } complete: (xhr) -> if xhr.readyState == 4 and xhr.status == 201 newItem.data.id = xhr.responseJSON.id return success() error() update: (items, success, error) -> newItem = items[0] $.ajax url: "/expenses/#{newItem.data.id}" type: 'PUT' dataType: 'json' data: { expense: newItem.data } .then(success, error) remove: (items, success, error) -> newItem = items[0] $.ajax url: "/expenses/#{newItem.data.id}" type: 'DELETE' dataType: 'json' .then(success, error) paging: true sorting: true columns: [ { field: 'date', title: 'Date', width: 100, format: "{0:MM/dd/yyyy}" }, { field: 'title', title: 'Title', width: 200 }, { field: 'amount', title: 'Amount', width: 80 }, { title: 'Actions', width: 70, buttons: [ { cls: 'editButton', commandName: 'edit', caption: 'Edit' } { cls: 'deleteButton', commandName: 'delete', caption: 'Delete' } ] } ] editing: enabled: true type: 'row' confirmation: delete: enabled: true template: (item) -> "Are you sure you want to delete expense \"#{item.title}\"?" toolbar: [ { buttons: [ commandName: 'insert' caption: 'Add Expense' ] position: 'top' } ]
This way way have a full coverage of all the CRUD actions for our expenses records and we can proceed with implementing the ShieldUI jQuery Chart Component to visualize the expenses data as part of a sample personal finance tracking application.