This tutorial will outline the steps required to create a sample inventory management application using RhoElements and RhoMobile Suite. The application will allow a user to scan barcodes and keep a running tally of how many times each item was scanned. To keep things simple, we will not be doing any synchronization in this part of the tutorial and will cover that topic later on.
Before we begin, make sure you have downloaded and installed RhoMobile Suite. Recall that RhoStudio is an Eclipse based IDE that allows you to write a mobile application using HTML, JavaScript and Ruby that will run on multiple mobile platforms. Each mobile platform’s development environment is used in the build process to compile a final executable for that platform. It is imperative that you have this complete development environment setup for each platform you will be building on. The prerequisites and setup for building on each mobile platform (for example, setting up an Android SDK) can be found here. In this tutorial we will begin by developing using RhoSimulator, but the final application will be running on a device.
After launching Zebra RhoStudio, let’s create a new project inside by selecting ‘File/New Project’. You should see a dialog appear like the one below. Select ‘RhoMobile application’ and then click the ‘Next’ button.
In the next screen, name the project “InventoryManagement” – be sure to keep ‘Use RhoElements’ checked and click Finish.
This will create a blank RhoMobile project with a directory structure similar to the one shown in the following image.
Let’s take a look at the file structure for a moment and explain what is going on. The ‘app’ folder, as it may sound, is where we will put the core application files including all of our data models and their corresponding views and controllers (more on that in a moment). The ‘icon’ folder contains the image use for the application icon. The ‘public’ folder will contain some subfolders to hold our CSS and JavaScript files. By default, RhoStudio includes jQuery Mobile/Jquery and corresponding CSS files. For the sake of this example, we will not be replacing any of these and we will be focusing on the ‘app’ folder contents. Recall that a Rhodes application follows a MVC (Model/View/Controller) approach and essentially the application is running a self contained web server. The user interface is primarily determined by the ‘Views’ or ‘.erb’ files. The ‘layout.erb’ file, as the name implies, defines the main layout for the application. If you open it up in RhoStudio, you will see something that looks very familiar to a typical HTML file.
You will notice typical html tags like:
<title>InventoryManagement</title>
You will also see Ruby syntax included in tags that contain percent symbols.
<% if is_bb6 %>
This is what is called inline Ruby syntax. If this file was called ‘layout.html’ then the ruby syntax would not be recognized, but since it has a ‘.erb’ extension, we can include ruby syntax. Typically this is done for conditional reasons, where you would like to change the HTML tags based on some conditions. You can see from the layout.erb file that there are several conditional statements that determine what style sheet to use based on the running operating system the application is executing on. We will come back to this file later on to modify the look of the application, but for now we will leave it alone.
Towards the bottom of the ‘layout.erb’ file you will see <% content %>
This is where the ‘main’ ui will be placed. Initially when the app is launched, the contents of ‘/app/index/erb’ will be used to populate the ‘content’ section. If you open that file up, you will see a small snippet of HTML and inline Ruby:
Before we add the data models we will use for the application, let’s compile the application and see what happens. Highlight your project folder in the Project Explorer (in this example, it is named InventoryMangement). Then from the RhoStudio menu, select ‘Run/Run Configurations’:
Select ‘RhoMobile Application’ and the ‘New_Configuration’ icon underneath. (You may need to right-click ‘RhoMobile Application’ and select New to get the ‘New_Configuration’ icon.) The Run Configurations window appears. Rename the run configuration from New_configuration to InventoryMangement.
Click ‘Run’. Be sure to keep the ‘Simulator type’ as ‘RhoSimulator’. You will see indications in the console tab that the project is compiling:
After a few moments you will see two new windows open: the simulator showing the application, and the ‘Web Inspector’. The simulator window shows how the application will look on the device. The ‘Web Inspector’ is a tool that can be used to help troubleshoot your application.
As you can see, the application does not really do anything except to show the contents of ‘/app/index.erb’:
<div data-role="content"> <ul data-role="listview"> <li><a href="#">Add link here...</a></li> </ul> </div>
The code snippet above is what is shown in the simulator. The ‘data-role’ part of the HTML tags is jQuery syntax that controls the look and behavior of the list item. Let’s close both of these windows so we can start to add the data models we will use for the application.
Right-click on your project folder in the Project Explorer. Select ‘New’ followed by ‘Rhodes model’ and name it ProductCatalog. It will have three attributes – Name, SKU and Image – and it will store information about the products in our inventory. Do not enter spaces between the attributes.
Pay attention to the case you are using for model attributes. Ruby is case sensitive, so it is recommended that you follow the same case sensitive approach through your code. |
Creating a model will add a new folder to the ‘app’ directory with the name of that model along with a set of prebuilt files for different views as well as the model controller to handle the logic for each of these views: index.erb: lists all ProductCatalog items new.erb: form for creating a new ProductCatalog item edit.erb: form for updating an existing ProductCatalog item show.erb: page that shows an existing ProductCatalog item
If you open these files, you will see they look very similar to the /app/index.erb we mentioned before. These files define how the page will look using a combination of HTML and inline Ruby syntax. All of the logic for this model is stored in the product_catalog_controller.rb:
You can think of these as functions or methods that can be executed for this model. As you can see, there is a corresponding method for each view that was created before. When a view is loaded, it will look for the corresponding method in the controller to execute prior to rendering the view. By default, ‘index.erb’ is loaded when no specific view is referenced. As you can see in the example, this will execute the ‘index’ method inside the product_catalog_controller.rb. This file is purely Ruby syntax. It will have Rhodes Mobile APIs available to the application as well as standard Ruby syntax.
Now let’s add this model to our ‘app/index.erb’ so that we can see how these methods are already plugged into the application. We will use these CRUD methods for our real application in the upcoming steps, but in a different manor. Open up the ‘/app/index.erb’ file and replace the line:
Select ‘Run/RunConfigurations’ again and click ‘Run’ after you selected the run project we set up before (it should be selected already). This time we see the new ‘Catalog’ entry:
If you click this, it will change the page to the ‘/app/ProductCatalog/index.erb’ page. We did not need to specify the full URL in the HREF attribute because we are already at the ‘/app’ level. So just saying ‘ProductCatalog’ was enough. Like with traditional web sites, index.html is the default file that is loaded when none is specified and likewise in our case, index.erb is loaded by default. Since we do not have any ProductCatalog records yet, nothing is displayed:
If you click the ‘New’ button it will load the ‘ProductCatalog/new.erb’ file and likewise execute the ‘new’ method in the ‘product_catalog_controller.erb’ file:
This essentially creates a new ProductCatalog item and assigns it to the variable @productcatalog. It also defines what actions to take if the ‘back’ button is pressed on that page.
Go ahead and create an item. It does not matter what you type in, we will be deleting it after you see that the model’s CRUD views and methods are working. Notice that in the ‘new.erb’ file, the POST action for the form is calling the ‘create’ method.
Select that item. Press the ‘Edit’ button. This will change the view to the ‘ProductCatalog/edit.erb’ file along with executing the ‘edit’ method inside the controller. Likewise the POST action for the ‘edit.erb’ form is to call the ‘Update’ method in the controller:
def update @productcatalog = ProductCatalog.find(@params['id']) @productcatalog.update_attributes(@params['productcatalog']) if @productcatalog redirect :action => :index end
Go ahead and delete that record as we will write some code to preload the ProductCatalog with some sample data.
To seed our initial database of products under the ProductCatalog, we will have a JSON file with sample data. In a real world scenario, you may choose to use AJAX and Web Services to retrieve your product catalog or you may also use RhoConnect to keep your product catalog synchronized (we will show you how to do this later on). To create the file, right-click on the ‘public’ folder under the application folder and click on New -> File to bring up the new file dialog. Name the file Products.txt and click Finish. This will create an empty text file which we will populate with sample data. Copy and paste the text below.
[ {"SKU": "12345", "Name": "Converse Hi-Top", "Image" : "data:image/jpeg;base64,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%3D%3D"}, {"SKU": "67890", "Name": "Skechers Womens", "Image" : "data:image/jpeg;base64,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"}, {"SKU": "12121", "Name": "Pointer Lace-up", "Image" : "data:image/jpeg;base64,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%3D"}, {"SKU": "22222", "Name": "Asics Pacewalker", "Image" : "data:image/jpeg;base64,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%3D%3D"}, ]
‘SKU’ is the barcode for an item, ‘Name’ is the name of the item and ‘Image’ contains the base64 string representation of the image related to that product. There are tools available online to convert an image to its base64 representation which you can use. This is also referred to as ‘DataURI’ and can be a nice way to handle images without having to have a whole bunch of physical files, you can keep it all in the data scheme. As you may recall, all of the UI is rendered though a browser and the <IMG>
tag displays base64 strings very nicely.
Save the file after copying the JSON string and open the ‘application.rb’ file under the ‘app’ directory. This code gets executed when the application starts up.
Add the following code before the first ‘end’ statement:
#Seed the database with initial data catalog = ProductCatalog.find(:all) if catalog.empty? fileName = File.join(Rho::RhoApplication::get_base_app_path(), '/public/Products.txt') lines = File.read(fileName) jsonContent = Rho::JSON.parse(lines) jsonContent.each { |json| ProductCatalog.create("SKU" => json['SKU'], "Name" => json['Name'], "Image" => json['Image']) } #finished creating database for real application you may # want to display a loading page to indicate to the user # something is going on else #The catalog has been loaded already there is nothing to do end
Save the file and close it. The first line of this code snippet tries to get all the objects inside of the ProductCatalog model. It then checks if the resulting collection is empty, in which case we have no records and we need to seed it with the JSON file. It then opens the ‘Products.txt’ file using the ‘File’ module. The line
Rho::RhoApplication::get_base_app_path()
refers to the Rhodes API for getting the path to the root of the application. After reading and parsing each line, a ProductCatalog entry is created using the data returned from the JSON file.
Let’s run the app in RhoSimulator again (Run/RunConfigurations), and see if the Product Catalog gets loaded. If you do not see the set of products that we had in the seed data, then most likely you did not delete all records from the previous steps. Recall that our code that we added to the initialize will load the seed data if there are no records in the ProductCatalog model. You should see something that looks like:
If you click on a item, you should see that all three properties have data from the seed file. If you do not, then you probably misspelled the properties when creating the ProductCatalog model (ex: ‘Sku’ instead of ‘SKU’). No need to worry, simply delete the ProductCatalog folder from the project and recreate the ProductCatalog model (recall we did not modify any of the prebuilt pages for the ProductCatalog yet).
Notice that the Image field in the detail view will show the raw base64 representation of the image instead of the actual image. To fix this, open up ‘show.erb’ under the ProductCatalog model and change the line
Now that we have our ProductCatalog created and pre-populated, let’s add a second model that will hold our Inventory information. For this model we will keep track of what SKU is scanned as well as the total amount of times it was scanned. Right click on the project’s ‘app’ folder and select ‘New/RhoMobile Model’ and call it ‘Inventory’ with attributes SKU and Quantity.
Open the ‘index.erb’ file under the ‘app’ folder again to add a link to the Inventory viewer. Do this by adding the following line of code under the “View Catalog” list item:
<li><a href="Inventory">View Inventory</a></li>
Save the file, run the project again, and click on the “View Inventory” link inside the app. The resultant page will be blank because we do not have any entries in the Inventory model yet. Click on the ‘New’ button on the top right of this screen to bring up the New Inventory screen with an option to add an SKU and a quantity for that item. Add an SKU number that you have used in the ProductCatalog model, set its quantity to 1 and click on ‘Create’.
This redirects back to the Inventory list with an entry for the inventory item that we just created. Repeat the creation process for two more SKUs.
Let’s now change the Inventory List view slightly to show the quantity and the item image in the same list. By default, you should see a collection of all the entries inside the Inventory model returned in the ‘@inventories’ variable. We will use this collection to change the display of the inventory list. Open the ‘index.erb’ file inside the Inventory folder.
Add the following code after the line <% @inventories.each do |inventory| %>
<% product = ProductCatalog.find( :first, :conditions => {:SKU => inventory.SKU} ) if product name = product.Name if product.Image isrc = product.Image end else name = inventory.SKU end %>
The <% @inventories.each do |inventory| %>
line picks up each Inventory entry using the ‘@inventories’ variable we declared in the code behind file and performs the operations listed above. We look up the ProductCatalog model to find the item’s catalog by SKU using the ‘ProductCatalog.find’ function. If we find an item for it, we get the name of the product and if it has an image, get the base64 of that image from the catalog. If we do not find the product in our catalogs, we simply set the name to be the SKU. To show the name, image and quantity in the list view, change the list item on this page as described below:
The code above sets up list item linking to the ‘edit.erb’ page for an Inventory object and sets up the HTML/CSS elements required to display a thumbnail of the image, the item name and the quantity in the same line. RhoMobile uses jQuery Mobile so we can use CSS class elements from it to construct our UI. Save the file and re-deploy the project. On the home screen, click on ‘View Inventory’ and you should see a list of the three Inventory items we created above, with their image, name and quantity scanned as a list. A sample is shown below:
Clicking on each item will show a details page with the SKU and Quantity as editable fields for that Inventory item. This page, in fact, is the ‘edit.erb’ page under ‘Inventory’. Now that we have setup a catalog, an inventory and a mechanism to display the inventory, we will setup a page that will allow us to scan a barcode to make entries in the Inventory model rather than manually adding them in.
Add a new file to the Inventory model and call it ‘scanPage.erb’. Open the file and add to it the following code:
<div data-role="page"> <div data-role="header" data-position="inline"> <h1>Scan a barcode</h1> <script type="text/javascript"> </script> </div> <div data-role="content"> <div id="divCountTotal"> <a href="/app/Inventory/index" data-role="button" id="numberScanned">0 Items Scanned</a></li> </div> <div id="divImageInventory" style="text-align:center" margin-top="10px"> <img id="iImage" src="/public/images/barcode.jpg" style="max-width:320px"/> </div> <div id="barcode" style="font-size:1.2em"> </div> <div id="productName" style="font-size:1.7em;"> READY TO SCAN </div> <div id="count" style="text-align:center;font-size:4em"> </div> </div> </div>
This code sets up our scan page with a section to add JavaScript (more on that later), a div for displaying the scanned barcode, the name of the item scanned, the number of times a product has been scanned, and the image of the scanned product along with the number of items scanned in total. Notice how we start off with an image ‘barcode.jpg’ as the placeholder for the product’s image. This is just a sample barcode image retrieved from the internet and placed under the ‘public/images’ folder under the root of the project. To test this, add a link to this scan page in the ‘index.erb’ file under the root of the app. Add the following list item below the ‘View Inventory’ link:
<li><a href="Inventory/scanPage">Scan a barcode</a></li>
Deploy the application and click on the ‘Scan a barcode’ link to view the page we just created.
Notice that we setup a button.
<a href="/app/Inventory/index" data-role="button" id="numberScanned">0 Items Scanned</a></li>
This will let the user click on the button to see the complete list of items inventoried (basically the default Inventory/index.erb file we modified before). Notice how we specify the path to the page.
Next, we will setup the controller to trigger the Scanner to start as soon as the scanPage is loaded. Open up ‘inventory_controller.rb’ under the Inventory model. Notice how there are functions for each ‘.erb’ file in the controller. This indicates the behavior of the application when a page is called so that the developer can add additional functions before the page loads. For example, we need to add code to turn the Scanner on before the app directs to ‘scanPage.erb’. To do this, we add a function inside the controller called ‘scanPage’ and turn the Scanner on before rendering ‘scanPage.erb’. The ‘scanPage’ function looks like:
def scanPage Scanner.decodeEvent = url_for(:action => :decodeEventCallback) Scanner.enable render :back => '/app' end
This function calls the Rhodes ‘Scanner’ class and firsts assigns a decode event callback. This function is what gets executed on a successful barcode decode. The ‘Scanner.enable’ line makes the scanner active for this page and the user can press the scanner button on the device to bring up the viewfinder and perform a scan. After enabling the scanner, the function renders the ‘scanPage.erb’ page and attaches the Back action to display the home screen, i.e. the ‘index.erb’ at the root of the ‘app’.
At the time of writing this tutorial, the Scanner object is only available on Zebra Hardware. You will need a device at this point to complete the remainder of the project. Alternatively, I could have chosen the Barcode object with slightly different syntax. Please consult the complete list of Mobile APIs as well as the API Compatibility Matrix to see which APIs are supported on which platforms. |
The ‘decodeEventCallback’ function is given below:
def decodeEventCallback barcode = @params['data'] product = ProductCatalog.find( :first, :conditions => {:SKU => barcode} ) if product.nil? product = ProductCatalog.create({"SKU" => barcode, "Name" => "Unknown Product", "Image" => "data:image/jpeg;base64,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%3D"}) end name = product.Name if product.Image WebView.execute_js("setImgSrc('"+product.Image+"'); ") end inventoryItem = Inventory.find( :first, :conditions => {:SKU => barcode} ) if inventoryItem.nil? inventoryItem = Inventory.create( {"SKU" => barcode, "Quantity" => 1} ) else itemCount = inventoryItem.Quantity.to_i itemCount += 1 inventoryItem.update_attributes( {"Quantity" => itemCount.to_s} ) end inventoryItem.save if itemCount.nil? itemCount = 1 end getInventoryCount WebView.execute_js("setProductData('"+name+"','"+barcode+"','"+itemCount.to_s+"'); ") end
Let’s look at this function line by line. When the decode event returns after a successful decode, it contains a few parameters (a full list is provided in the RhoElements API for Scanner) out of which we extract the ‘data’ element which contains the barcode that was just scanned. With that barcode, we find the ProductCatalog entry we may have for that product by matching the ‘barcode’ variable to each product’s ‘SKU’. If we do not have an entry for that barcode, we create a new one with a default ‘Name’ and ‘Image’.
If we have an entry in our ProductCatalog model, we fetch the item’s name and image to be displayed on the page. If we find an image, we want to display it on the scanPage.erb. In order to communicate from the Ruby controller to the rendered page, you must use the Rhodes WebView object. This object has a function called ‘execute_js’ which allows you to call JavaScript functions as well as pass variables to that function:
WebView.execute_js("setImgSrc('"+product.Image+"'); ")
This will execute the JavaScript function ‘setImgSrc’ (which we will create in a second) from code behind and pass as arguments the base64 representation of the image we fetched from the ProductCatalog model.
The decode event callback then tries to find an entry in the Inventory model for the product that we just scanned so that we can fetch the Quantity parameter to determine how many of this product have we already scanned. If the result of the find is nil, it means we have no entry for this product in our Inventory model in which case we create an entry by using ‘Inventory.create’ and set its Quantity to 1. This ‘create’ function, as well as others, can be executed on any data model that you have created. We pass in a Ruby hash that essentially has a list of property names and their values.
If we do find an entry in the Inventory model, we fetch the Quantity saved in the database, convert it to an integer by using ‘Quantity.to_i’, increment it by one and update that record by using ‘inventoryItem.update_attribute’. Finally we save this change by executing an ‘Inventory.save’. The block of code after this step that checks to see if the itemCount is nil is used when we scan an item for the first time. In that case, the itemCount will be nil and we initialize it to 1 just for ease of displaying on the screen. Then we call a ‘getInventoryCount’ method in the controller to count the total number of items we have scanned. Create this method in the inventory_controller.rb:
def getInventoryCount items= Inventory.find( :all ) scanCount = 0 items.each do |item| scanCount = scanCount + item.Quantity.to_i() end WebView.execute_js("setProductCount('"+scanCount.to_s+"'); ") end
This method first gets a collection of all the items inside of the Inventory model, iterating through each of them and fetching the Quantity field and adding it to our ‘scanCount’ parameter. We then call another JavaScript function to display the total.
Now we have added all of the code to the controller, let’s go back to the scanPage.erb and add the JavaScript functions we are calling.
$('[data-role=page]').live('pageshow', function (event) { $.get('/app/Inventory/getInventoryCount', { }); }); function setProductData(name, SKU, count) { if (!document.getElementsByTagName) return; document.getElementById("barcode").innerHTML = SKU; document.getElementById("productName").innerHTML = name; document.getElementById("count").innerHTML = count; } function setProductCount(scanCount) { var itemtext = scanCount + " Items Scanned"; $('#numberScanned .ui-btn-text').text(itemtext) } function setImgSrc(data) { document.getElementById("iImage").src = data; }
In the above code you will see mention of one JavaScript function we did not speak about before.
$('[data-role=page]').live('pageshow', function (event) { $.get('/app/Inventory/getInventoryCount', { }); });
This statement is jQuery syntax that effectively executes a function when the page is completely ready to handle JavaScript. The $.get method is an Ajax passing the URL as a parameter. In order to communicate from the webpage via JavaScript to the Ruby controller methods, is through Ajax. The URL we pass is calling the getInventoryCount method we added inside the controller above. Like we mentioned before, this method in turn uses the WebView.execute_js function to talk back to JavaScript and the rendered page.
One other thing we will do here is remove the default Rhodes toolbar, since we want our UI to take up most of the real estate. This is easily accomplish by going back into the ‘app/application.rb’ file. Look for the line:
#@@toolbar = nil
And remove the ‘#’ to uncomment the line.
That’s it! We just finished creating our inventory management application. Since we are using the ‘Scanner’ class from the Rhodes framework, we will need to deploy this application on a device in order to see the Scanner library. Attach a device to your computer and re-deploy the application, only this time selecting ‘device’ as the simulator type and the platform corresponding to your device. While creating this application, a Windows Mobile device was used and the screenshot below reflects that. The application will take longer to deploy on a device than a simulator and hence it is advisable to keep an eye on the Console window inside of Eclipse to determine when deployment has completed before using the application.
If you close the application and reload it, you will see that all items in the data models have been retained. We could now spend some time modifying the style of the pages and changing the page flow, but for now we will stop here. In another tutorial we will show you have to add RhoConnect data synchronization services so that the ProductCatalog can some from a centralized source as well as show how to get the Inventoried records up to a backend for storage.