Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
140 lines (79 sloc) 11.3 KB

Lesson 2: Connecting to Server Data Source

Next we will connect the application that we built in Lesson 1 to a web service and sync local data with the remote data source.

Typically when developing a connected mobile application, there is significant complexity in having code running locally, code hosted on the server and code running on a device. With RhoHub’s hosted IDE and hosted sync, your middle-tier “source adapter” is automatically deployed and you can build for multiple platforms without setting up a complete dev environment locally. In the diagram below you can see how your app, whether running in the simulator on your development machine or installed on a device connects to RhoHub where your source adapter is developed hosted.

Note: if you want to, you can develop locally and upload the source code to RhoHub.

Users and Logins

It is important to understand how your rhodes client connects and logs in into rhohub (and rhosync). Your rhodes client will login and create a session with rhohub. It will use this session to issue create, read, update or delete instructions from the client to rhohub. Typically, these rhodes to rhohub sessions are good for 1 year, and so you only have to login from the client when you initially install. As needed, rhohub will in turn establish a connection and login to your server data source (aka backend) to create, read, update or delete records using code your write in your source adapter (see below). The user names and passwords for those systems can be the same or totally different, and rhohub may have to re-authenticate itself every time your source adapter runs. In some cases, a backend system may not require any login at all, example an application that reads publicly available RSS feeds. However, you always need to have a login between the rhodes client and rhohub.

There are two approaches available.

1. Create a user in rhohub.

This is the simplest way to get started and what follows in the tutorial. Login from your rhodes client using that login and password. A disadvantage of this approach is that you have to create these users ahead of time in rhohub which makes it hard for for arbitrary new users to connect (see next section). Next, you have to subscribe the user you just created to your application because when a client connects with the user name and password you set up, rhohub will check if they have permission to sync with the given application and if not will reject your client’s sync request. Lastly, you can add credentials to the subscription you created. Credentials are information like the real backend user name and password and URLs that are saved in the rhohub database and later passed to your source adapter when it executes. Credentials are optional.

For example, you create user a new user john with password mobile in rhohub. This login and password are only used between the rhodes client and rhohub. Subscribe him to your application. Now in johns subscription, you can set his credentials to be john.adams123 with password enterprise because that is what John uses to login to your enterprise system. John can login from his client using john and mobile, but rhohub will save, and your source adapter will have access to john.adams123 and enterprise when it runs and john’s device is syncing.

Tip: if you do not care to limit access on a per user basis, you can hard code a shared login and password into your client application. This approach is generally not suitable if you need to display different data for different users however.

2. Delegated Authentication

Because we usually don’t know ahead of time which users will be accessing an application, and we don’t want to keep a 2nd set of user names and passwords in rhohub, we created delegated authentication. Using delegated authentication your backend application is responsible for logins and passwords instead of rhohub. The rest of this tutorial doesn’t use delegated authentication as it is a slightly more advanced topic. To read more about delegated authentication, please see http://wiki.rhomobile.com/index.php/Delegated_authentication.

Subscribe User

In order for your application to connect to the server, you will need to subscribe a user. You can use the same user and credentials that you use to log in to RhoHub; however, it is advisable to create a test user so that you can publish your experimental application for others to use. To create a new user, click on “Dashboard” then select the “Users” tab, click “Add User” and create a user named “tester” with the password “tester” with your email address.

Then to go back to your application, click on “Dashboard” and choose “Inventory” from your list of applications. Then click on the “Settings” tab in RhoHub and scroll down to the Permissions panel at the bottom of the screen.

Check the “tester” user and leave the other fields blank, then click “Save.”

Creating a Source Adapter: Query

Go to RhoHub in your browser and click on the “Editor” tab in the Inventory project. Under the “Server” tab, select “product.rb” — this is a template the was generated by the application creation wizard.

If this was an application that required us to login to see the products, we would implement login, but for now, just delete the implementation of the login method so it doesn’t raise an exception. The example shop on heroku we are using does not require logins. We will modify the code to connect to a mock back end, which you can see at: http://productshop.heroku.com/

Next we will implement the query method to fetch the list of products so that we will be able to display them on the phone.

Query is called every time that the client syncs with the server.
We’ll use an XML API to access a list of products. You can see the data we will fetch by looking at it in your browser: http://productshop.heroku.com/products.xml

In RhoHub, we’re not in the Rails enviroment, so we need to require the libraries we’ll be using. We’ll use nokogiri for XML parsing and open-uri to access the URL over http. Put the following two lines at the top of product.rb:

require 'nokogiri'
require 'open-uri'

The code to implement the fetching of the data from the web service needs to be in the query method. We’ll do the data transformation, right after fetching the data:

def query
      @result = {}
      xml = nil
      open("http://productshop.heroku.com/products.xml") do |f|
          xml = Nokogiri::XML(f.read)
      end
      xml.xpath('./products/product').each do |product_node|
        id = product_node.xpath("./sku/text()").to_s
        attr_hash = {}
        product_node.children.each do |attr_node|
          attr_hash[attr_node.name] = attr_node.text
        end
        @result[id] = attr_hash
      end
    end

The query method reads the XML data from the productshop web service, then iterate through each XML node and transform it into a Rhodes “generic result” which it stores in @result. The format of this generic result is a hash, where each key is a unique string with a value that is a hash of object attributes. For example, if there were two products, we would want to create a result like this:

{"88"=> {"brand"=>"Ruby", “name”=>"Rails", “price”=>"$1000000000.00", “quantity”=>"1", “sku”=>"88"} “900”=>{"brand"=>"Ford", “name”=>"Hovercraft", “price”=>"$30,000", “quantity”=>"1", “sku”=>"900"}}

Click Save!

Test your source adapter

To test your source adapter, click “Show Records” at the top-right of the Editor panel. (Note: this will automatically reload the source adapter into the running sync server). Note that the “Show Records” button acts on the selected source adapter file. (“product.rb” is selected by default, so you don’t need to do anything in this case.)

You should see a list of IDs, which you can open to see their contents. The screenshot below shows that the server had 4 records at the time of this writing. The record with id (sku) “100” has been open to reveal its attributes.

If your code had an error such that the query method raised an exception, the console will automatically open and display errors. However, if the format is correct and no exceptions were raised, the console will remain closed. If you are not seeing the data you expect, click on the arrow to see the console output. You can add “puts” statements to your code to analyze what is going on. You can also view the log by clicking the “View Logs” button (next to the “Show Records” button).

Sync Remote Data to the Device

With the implementation of the source adapter, which is automatically deployed on RhoHub, you can sync data from the device. Note: you don’t need to update the application in the simulator since we only modified server code.

To sync, you will need to login using the following steps. (Note: later you can develop your own UI that will present a login screen or automatically log in for anonymous access.)

Clicking “menu” on the device chrome will bring up an array of six choices. Then choose the “more” option:

You will next see a menu. Select “Options”

This takes you to the Rhodes Setttings page which was auto-generated and is part of your application. (You can see the source to this page under the Client tab on RhoHub: app/Settings/index.erb)

Click the “Login” link which will take you to the login page (app/Settings/login.erb)

Now type login “tester” and password “tester” and click login. You will be directed to a wait screen and when login is complete, you will see the product page again. This will show you local data, since the start page is rendered immediately after login, but before sync is complete. If you refresh the screen you will see the remote data.

What happened to your local data? Well, we’re not done yet. The local data is trying to sync to the server, but if you recall, we have not yet implemented the create method which will sync the local data to the remote web service.

Sync Local Data to the Remote Web Service

Implement a create method. Note that you will need to add the requires at the top of the file.

require 'net/http'
    require 'uri'
def create(name_value_list,blob=nil)
      attrvals={}
      name_value_list.each { |nv| attrvals[ "product[" + nv["name"] + "]" ]= nv["value"] } # convert name-value list to hash
      res = Net::HTTP.post_form(URI.parse("http://productshop.heroku.com/products/create"),attrvals)  
    end

You can test it, by clicking “Create Records” at the top of the source adaptor code editor panel. Fill in some attributes (including a unique sku) and click “create.”

This will call your source adapter’s create method, which in turn calls the web service to save the data remotely. You should see a new record added to the list. Now in your application which is running in your local simulator, go to Options (or Settings) and select “Perform Sync” — you should see your new record along with the remote data that was there before.