In the previous two parts of the tutorial (first part and second part), you have been guided through the coding of a complete Ruby on Rails backend in part one, that can be used to register and login users through a JSON API that can be consumed by the Android native app we coded in part two.
In this third part of the tutorial I want to further extend the functionalities of our Android app and its Rails backend in order to allow the actual creation and editing of tasks through the exposed API.
Let’s start by securing a bit more the API, then we will proceed to enable the creation of new tasks
Since I posted the tutorial I got some good advices on how to improve the API’s security, for example not passing the auth_token as a GET parameter but in the HTTP Headers.
According to this response to a similar question on the official Devise Support Group, we need to override the params_auth_hash of the TokenAuthenticatable module.
Add the following code to the devise.rb initializer in the config/initializers/ directory, just inside the Devise.setup block (for example at the end, before the closing “end”).
Having done so it’s now possible to request the tasks to the API passing the auth_token inside the headers. Restart your Rails application and use curl from the command line to retrieve our (fake) tasks:
You should receive the hard-coded tasks as usual.
It’s now the turn of our Android app to be modified to send the auth_token as a header when asking the tasks to the API.
To do this I decided to slightly modify the UrlJsonAsyncTask and JsonHelper from the library we used created by Tony Lukasavage.
I forked the original project on GitHub and made the modifications to the code. You can download the forked library here.
I added to the JsonHelper a new parameter - authToken to be passed to the get*FromUrl() methods that will be added to the HTTP Headers in the getStringFromUrl() method:
The auth_token will be passed to the JsonHelper from the modified UrlJsonAsyncTask that has gained a new attribute authToken, with its own getter and setter. We will use the latter in our HomeActivity to pass the saved token our app received and saved in the properties after the login.
To finish up all this changes made to our app, just modify the loadTasksFromAPI() method in the HomeActivity
As you can see we are not passing the token as a GET parameter in the url but passing it to the GetTasksTask (that is extended from UrlJsonAsyncTask) thanks to the new setter method.
It’s now time to compile the app and test it. Everything should run as before, but now it will be more secure!
A real task
First of all we need to get rid of our fake tasks we setup in the previous tutorial. Let’s start creating a real model for the Task. We just need a title and a completed attributes. I also associate every task to the user who creates it.
Generate the new model and the migration:
I added a default scope to order tasks based on the completion status and how old are they. In this way, when we receive them from the API, they are ordered as not completed first, done last and newer on top.
Don’t forget to add the has_many association to the User model.
Finally migrate the database.
To generate the API from our controller we will use the Rabl gem. It’s basically a builder to render JSON views and you can watch a nice screencast by Ryan Bates to learn more about it.
Let’s just add the gem to our Gemfile:
And run the bundle install command to install it. You also should add an initializer to the app to specify that you don’t want to add a root element to the JSON response and the children elements of the API. More info about that can be found in the Railscast linked above and in the official documentation of the Rabl gem.
It’s now time to remove our fake index action JSON response from the TasksController and provide some real data to our Android app.
The index action is really simple! We just find the tasks associated with the current user, authenticated through the auth_token provided with each request to the API. All the work done so far is finally paying off.
To use Rabl we need to create a new file in the views directory with the “.json.rabl” extension: the first to specify the format that it will provide and the second to use the correct builder.
Rabl, in my opinion, is not so easy to understand at first; but using the documentation and via a trial and error process you can wrap your head around it.
In this view I wanted to provide the same JSON format we faked before and use the same fields of the other part of the API, such as the user registration and authentication.
The object false tells to the Rabl builder we don’t want to map the root-level of the response directly to any object and we construct the nodes freely.
I added two nodes with a success and info information that will be used by the Android app to check if everything is ok with the response and provide a message.
I also added a node with the tasks count that can come in handy.
You can test the real index action through the API with a curl command (the tasks will be empty if you haven’t created any).
We are now able to requests the list of the tasks for a given user but we still need a way to create a new one. Let’s add the create action to the TasksController.
As you can see we are building the new tasks against the current user tasks and rendering the created object with a Rabl JSON view. If something goes wrong the controller will render directly a response with an error message.
The Rabl view is similar to the one we used for the index action: we just render the attributes for a single task and the additional nodes to give some more information about the response.
To finish up this last step, don’t forget to add the new create route to the app routes (the index action was already mapped before).
To test the creation of a new task, just use this curl command and watch the response back from the API.
Remember that the auth_token used in these examples are random and provided by my own instance of the app. Use the ones created for your own users, as already specified in the previous part of the tutorial.
Having completed the coding of the backend end point of the API, it’s now time to add the new feature to the Android app. In order to create a new task, the app should provide a new Activity with a text field and a save button.
This new Activity would be launched from the app action bar/menu, so we need to add a new item to it and catch the click on the new task button. Add the new menu_new_task string to the strings.xml resource file.
In order to launch the new task Activity, add a new id to the switch case in the onOptionsItemSelected() method of the HomeActivity class. When a user will click on the “New Task”, the NewTaskActivity will be launched.
Having added the additional code to manage the launch of the NewTaskActivity, it’s time to actually create this new activity:
Open the menu File > New > Other ... > Android Activity and name the new file NewTaskActivity.
You can see the code for this new class here:
The Activity is very similar to the RegisterActivity and as you can see the code is almost copied verbatim.
The differences are mainly in the CreateTaskTask class extend from UrlJsonAsyncTask that is called by the saveTask() method when the user click on the save button.
The CreateTaskStak doInBackground() method sets up the JSON request with all the right attributes (the auth_token taken from the SharedPreferences and the value of the text field) and sends them to the API end point.
The onPostExecute method instead close the activity in case of success and launch the HomeActivity again.
The following code is the actual layout used for the NewTaskActivity: it’s a simple EditText field and a Button. Remember to add all the necessary strings to the strings.xml resource file.
Finally, before compiling the Android app with the new feature, don’t forget to add to the manifest file the new activity:
If everything goes right in the compiling process, you should see this new shiny activity that will allow you to create new tasks from the Android app directly to the Rails backend, using the improved API we coded earlier.
The NewTaskActivity layout (GingerBread 2.3 left and Jelly Bean 4.1 right, with the Sherlock Holo theme)
Completing Tasks: the Rails part
This is the last stretch of this long tutorial, bear with me just for a few lines of code more.
To actually do something with our tasks, we need a way to check them as “completed”. We already have an handy attribute to mark the task but it lacks a method to do so.
Reopen the Rails application and add these two new methods to the Task model.
I added non only a method to complete the task but also one to (re)open it: the user of our Android app should be able to check/uncheck his or her tasks.
The two new actions will update the task and render the JSON response back if everything is ok. I added a rescue for the RecordNotFound exception in order to render a proper response for this situation within the API.
Here are the two new views for the open and complete actions.
I’m sure there is room for some refactoring and removal of duplicated code, but I leave this task to you.
Finally add these two new actions to the routes, inside the :api namespace, after the tasks index route.
You can try the complete action via the API with the usual curl command (provided you have a task already created):
Completing tasks: the Android part
For the last time in this series of tutorials, we need to open Eclipse and make some changes to the code of the Android app.
Open the HomeActivity file and start coding the last lines of code. I add another constant with the url of the tasks “toggle” endpoint of the API. We will add the task id and the required method (open or complete) when we will send the request in another method.
Before starting to add the code to actually toggle the completion of a task, we need to refactor some existing methods. When the GetTasksTask class populates the tasks list with the objects retrieved from the API, instead of pushing just the titles of the tasks from the JSON response in an array, the methods populates an ArrayList of Task objects.
The for loop creates the new tasks to be added to the array with the given attributes extracted from the JSON response.
I also changed the way we handle the ListView items, creating a custom Adapter instead of using a normal ArrayAdapter.
Note that I changed the layout for the list items from simple_list_item1 to simple_list_item_checked that uses the CheckedTextView instead of a simple TextView to render the items.
The actual code of the Task class is as follow. It’s basically a Java implementation of the Ruby class, with the id, title and completed attributes and their getters and setters.
Just create a new class from the menu File > New > Class and name it Task.
The code for the custom adapter could be added inside the HomeActivity class file at the end before the closing braket.
Particular interest in this code should be noted to the getView() method where it sets the CheckedTextView attributes from the Task:
the setText() method uses the task’s title
the setChecked() method sets the “checked” mark based on the state of the completed attribute of the task
a onClickListener() is set for the list item (see the onClick() method)
the setTag() method assigns the task’s id to the tag to grab it when it’s clicked and use it to call the API
The onClick() method simply calls the API based on the checked status of the clicked list item: if it’s checked (e.g. completed) send the request to the “open” action, otherwise to the “complete” one. The url is composed of the constant we set earlier, the task’s id extracted with the getTag() method from the list item and the correct action to call (open or complete).
The toggleTasksWithAPI() method is very simple and it just instantiates another class extended from the UrlJsonAsyncTask and sets the title for the dialog and calls the execute method with the provided url as we have seen above.
We are almost there! The last class we need to add to the HomeActivity is the aforementioned ToggleTaskTask. As you can see it’s very similar to the RegisterTask we coded in the previous part: it setups the json request with the correct headers with the auth token and executes.
Note that we are using the HttpPut class instead of the HttpPost one because our API responds to the PUT http verb for the open and complete actions.
The onPostExecute() method just shows a Toast with the success or error message coming from the API.
The HomeActivity with some real tasks and checked marks (GingerBread 2.3 left and Jelly Bean 4.1 right, with the Sherlock Holo theme)
We made it!
It’s time to compile the app, fire up the Rails app (or push it to your server or to Heroku, if you followed the previous tutorial advice) and try it out. If everything went fine you should be able to register and login a user, create new tasks and mark them as completed, all by using a secure API exposed from your Rails application.
I think that by following every steps in this series of tutorials you will be able to build both the Rails backend and the Android app, but I know that it’s easier to look at the code when it’s already completed and not split in snippets. So in the next few days I will push the two applications to GitHub so you can read the code from there or directly clone it on your local development machine.
I know that the code isn’t the best you could write, but it’s working and I believe that it’s a good starting point for a newbie. I wrote these tutorials as the tutorials I wished I had when I started coding these kind of topics, so I hope you will find them useful.
For every question or doubt, just leave a comment below. If you need to contact me directly, you can do it by sending an email to firstname.lastname@example.org