Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Rest With Rails Part III - Using ActiveResource

DZone's Guide to

Rest With Rails Part III - Using ActiveResource

· Web Dev Zone
Free Resource

Add user login and MFA to your next project in minutes. Create a free Okta developer account, drop in one of our SDKs to your application and get back to building.

It is easy to use open-uri and Net::HTTP. Well, easy is a relative term. Building a client library to access our task manager service will still require a fair amount of boilerplate code, more than we care to write, test and maintain. We also showed you some principles and conventions for designing RESTful Web services, and in this final part of our three part series we'll take it a step further and show you how we can use them to develop a client library for the task manager using ActiveResource.

If you missed parts one and two of the series you can find them here:

  1. REST With Rails Part 1
  2. Rest With Rails Part 2 : Serving XML, JSON and Atom 

This article series is based on chapter 5 from Ruby in Practice by Jeremy McAnally and Assaf Arkin. Courtesy of Manning Publications. All rights reserved.


PROBLEM

[img_assist|nid=4838|title=|desc=|link=url|url=http://www.manning.com/mcanally/|align=right|width=139|height=174]With the task manager service up and running it's time to move forward and develop our workflow application, and as part of that application we'll need to create and manage tasks. We want to reuse our task manager service, and we want to get it done before the day is over.

SOLUTION

We're going to build a client application that uses the task manager service using ActiveResource. We'll start by writing a class to represent the resources for handling a task list and individual tasks:

class Task < ActiveResource::Base
self.site = 'https://john:secret@taskmanager.example.com/'
end

We're using the URL to specify the username/password for accessing the service, and these map to HTTP Basic Authentication, using HTTPS when we need to access it over public networks. We've yet to write a single line of code, but let's first see what we can do with our new Task class. Let's start by creating a new task:

task = Task.create(:title=>'Read about ActiveResource', :priority=>1)
puts 'Created task #{task.id}'
=> 'Created task 1'

Doesn't this code look awfully familiar? We're using ActiveResource here to operate against remote resources, but the patterns are the same as the previous section, where we used ActiveRecord to access the database. Let's go and see what happens behind the scenes of the create method:

task = Task.new
task.title = 'Read about ActiveResource'
task.priority = 1
task.save

It starts by creating a new object in memory and setting its attributes, and saves the object by making a POST request to the resource /tasks, with an XML document containing the task definition. Our simple implementation receives the XML document, parses the attributes and uses them to create a record in the database. It then tells the client what the new task resource is, which is all our ActiveResource needs to know. Let's follow up by updating the task:

task.title << ' and try this example'
task.save

This time, since the task already exists, we make a PUT request to the resource and update. So we can create and update resources. We can also read and delete them:

task = Task.find(1)
task.delete
tasks = Task.find(:all)
Task.delete(tasks.first.id)

All of this is just a matter of conventions. ActiveResource follows the same conventions we used when we built the task manager service, so we got all this functionality just by specifying a URL. How do we know our Task class sends requests to the right URL? We assumed it uses XML by default, is there a way to find out for sure? Let's try the equivalent of the rake routes task:

puts Task.collection_path
=> /tasks.xml
puts Task.element_path(1)
=> /tasks/1.xml

We built our task manager around all the common pattern, but also added two resources specific to our task manager. We had one resource for listing all the completed tasks, and we'll want to use that from our client as well, so let's list those:

Task.find(:all, :from=>:completed)

As you can guess, this just is a request against the /tasks/completed.xml path. We also had a resource for quickly updating the task priority, which we designed to support our AJAX controls. Let's try to use that as well:

task.put(:priority, nil, 5)

This time the request goes to /tasks/{id}/priority, substituting the task identifier in the URL template. The put method takes two additional arguments, the first being a hash that is passed along as query string parameters, and the second being the body of the message. We're passing a priority number in the body of the message.

As you can expect, there are other custom methods you can use like get, post and delete. We're going to hide the details of put from the application by wrapping it in a method; in fact, we'll add a couple more to create an ActiveResource class that represents our task manager service.

class Task < ActiveResource::Base
self.site = 'https://taskmanager.example.com/'
def self.completed
find(:all, :from=>:completed)
end
def self.update_priority(id, value)
Task.new(:id=>id).priority!(value)
end
def priority!(value)
put(:priority, nil, value.to_i)
end
end

Now let's try it out:

Task.site.user_info = 'john:secret'
puts 'Completed tasks'
puts Task.completed.map { |task| task.id }.to_sentence
=> "1, 2 and 3"
puts 'Changing priority for task 123'
Task.update_priority(123, 5)
puts Task.find(123).priority
=> 5

DISCUSSION

As you’ve seen from our examples, Rails makes it extremely easy to build Web services that follow the REST principles and work equally well with Web browsers and the programmable Web. In fact, a lot of that simplicity comes directly from following these principles. We didn’t have to tell our client how to create, read, update or delete the resource, those all followed from using the proper HTP methods. All we had to do is point our client at the right place. Likewise, we didn’t have to build two different task manager applications, one that people can use and another to service applications, we managed both at the same time by using different content types.

If you follow Rails conventions, you get the basic CRUD operations for free. In practice that’s often not enough, and you’ll find that you need more specific resources and layering additional actions into your controllers. We showed you how easy it is to add these custom methods on both the server and the client side. There are of course other things you’ll need to do, a fully functional task manager would need to handle deadlines and exceptions, send notifications, even spawn workflows that would involve even more tasks and interact with other services. Those are all possible to do within the constraints of REST.

In the last three solutions we talked extensively about Rails, but we want those to be lessons you can take with you if you use other Web frameworks or even other programming languages. One was the recommended practice for building RESTful Web services and the benefit that comes from following the REST architecture style. The other was the benefit of picking up on conventions and how they can help you design better, develop faster and end up with code that’s easier to understand and maintain. If nothing else, there would be less to document. Conventions are not just for Rails, when you’re building your own application think how conventions could help you work less and get more done.

The SOAP messaging protocol is another way to harness the HTTP protocol and build services that cross languages, platforms and applications.

Launch your application faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}