Jacob Orshalick is a software consultant, open source developer, and author. He is the owner of solutionsfit, a consulting firm dedicated to aligning businesses with technology. His software development experience spans the retail, financial, real estate, media, telecommunications, and health care industries. Jacob is a DZone MVB and is not an employee of DZone and has posted 13 posts at DZone. You can read more from them at their website. View Full User Profile

Mobile In Minutes With Sinatra

11.06.2012
| 1992 views |
  • submit to reddit

 Sinatra is described as a DSL for quickly creating web applications in Ruby with minimal effort. Sinatra makes it extremely easy to host a web application and expose RESTful services. Here we’ll show how this allows you to get mobile applications up and running in minutes with Sinatra.

Quick Introduction to Sinatra

The following ruby file is a valid RESTful service with Sinatra:

require 'sinatra'
require 'json/pure'

get '/hello/:name.json' do
  content_type :json
  {
    "message" => "Hello #{params[:name]}!"
  }.to_json
end

Here we are telling Sinatra to respond to any GET requests to the URI pattern /hello/.json. The inserted name is passed to the method as a parameter through the params hash. We set the returned content_type to JSON to ensure correct handling from the client and our hash is converted to a JSON response using json_pure.

To run this example, save the above code snippet to file named hello.rb. Then install and run your new application with Sinatra:

$ gem install json_pure
$ gem install sinatra
ruby -rubygems hello.rb

Now navigate to the URL http://localhost:4567/Jacob (feel free to use your own name) and you will be presented with:

{"message":"Hello Jacob!"}

Now we can easily consume that service with a jQuery script and host the script with Sinatra:

<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script>
      $.getJSON('/hello/Jacob.json', function(data) {
        alert(data.message);
      });
    </script>
  </head>
  <body>
  </body>
</html>

Here we use jQuery’s getJSON method to retrieve the JSON data from our service. The message from the JSON result is then alerted to the user.

To run the example, create a folder named public in the same directory where you created your hello.rb file. Inside that folder copy the above code snippet into a file named hello.html. Now navigate to the following page in your browser http://localhost:4567/hello.html. You will be alerted with the message “Hello Jacob!”

Creating a Mobile App with Sinatra

That was easy enough, but let’s see how we can apply this to a mobile setting. For this example, let’s create and consume a Sinatra service using jQuery Mobile.

Downloading and Running the Example

The example can be downloaded in its entirety here. To run the example, unzip the downloaded file to a known directory and execute the following commands:

$ cd /unzipped/folder/directory
$ gem install json_pure
$ gem install sinatra
$ ruby -rubygems cameras.rb

Now navigate to the following page in your browser http://localhost:4567/cameras.html. You will see the list of cameras for selection.

Exposing the RESTful Service

Let’s first create our RESTful service which will provide a top 10 list of popular DSLR cameras:

require 'sinatra'
require 'json/pure'

get '/cameras/top10.json' do
  content_type :json
  [
    {
      'id' => 1,
      'title' => 'Canon Rebel T3 DSLR',
      'description' => '...',
      'price' => '499.99
    },
    {
      'id' => 2,
      'title' => 'Canon Rebel EOS DSLR',
      'description' => '...',
      'price' => '349.99'
    }
    # ... ...
  ].to_json
end

In this case we are just constructing a hash that we then return back to the client in the same manner as our previous example. We could also retrieve the list of cameras from a database call, through an aggregation service, etc.

Setting up jQuery Mobile

Now we can consume the service with jQuery Mobile and host our mobile application with Sinatra. There will be two parts to our jQuery Mobile application, the HTML page which performs the setup for jQuery Mobile and a script which consumes our service. Let’s first take a look at the HTML page:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Top 10 Cameras</title>
  <link rel="stylesheet"
    href="//code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="cameras.js"></script>
  <script src="//code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js">
  </script>
</head>
<body id="page_body">
  <div id="cameraListPage" data-role="page">
    <div data-role="header">
      <h1>Camera List</h1>
    </div>
    <div data-role="content">
      <ul id="cameraList"></ul>
    </div>
  </div>
  <div id="cameraDetailPage" data-role="page">
    <div data-role="header">
      <h1>Camera Detail</h1>
    </div>
    <div id="cameraDetailContent" data-role="content">
    </div>
  </div>
</body>
</html>

The logic above is really just standard jQuery Mobile. We specify two pages, a #cameraListPage and a #cameraDetailPage. The #cameraListPage has an empty <ul> element which we intend to dynamically fill with cameras from our service. Similarly, the details page has no content which will be dynamically determined by selecting a camera from the list.

Rendering the Camera List

Now let’s have a look at the script that populates this logic. You can view the script in its entirety by downloading the example. The render method populates our <ul> by invoking our newly created camera service:

function render() {
  $.getJSON('/cameras/top10.json', function(data) {
    this.cameraData = data;
		
    var cameraListHtml = '';

    $.each(this.cameraData, function(i, camera) {
      cameraListHtml += '<li><a data-index="' + i + 
        '">' + camera.title + '</a></li>';
    });
		
    var $cameraList = $('#cameraList').append(cameraListHtml).listview();

    $cameraList.find('a').click(function() {
      displayCameraDetailPage(this, data);
    });
  });
}

Notice that the service data is retrieved in the same manner as our example above. The key difference is that we dynamically construct list items for each camera with a link that holds the index of the camera it refers to. The list items are then appended to the #cameraList which is rendered as a jQuery Mobile listview.

Showing the Camera Details

The final step is displaying the camera details. The displayCameraDetailPage method is bound to each camera link that was generated. The method is passed the <a> element and the camera data we retrieved from the service.

function displayCameraDetailPage(element, cameraData) {
  var camera = cameraData[$(element).data('index')];

  var detailsHtml = 
    '<div data-role="content"><h2>' + camera.title + '</h2>' + 
    '<p><strong>Price:</strong> ' + camera.price + '</p>' +
    '<p>' + camera.description + '</p>' +
    '</div></div>';
	
  $('#cameraDetailContent').html(detailsHtml);

  $.mobile.changePage('#cameraDetailPage');
}

Here we make use of the jQuery data method to retrieve the index of the camera that was selected. A markup representation of the details of the camera is generated and the #cameraDetailPage content is updated. Once the update is complete, the jQuery Mobile changePage method is used to show the #cameraDetailPage.

Sinatra makes it easy to develop web applications quickly. Try it and your sure to get your next mobile application up and running in minutes.





Published at DZone with permission of Jacob Orshalick, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags: