Due to the removal of ActiveResource (Ares) from Rails I want to analyze how we use it, how we can replace it, and present a new promising gem.
ActiveResource was introduced in Rails 2.0:
Active Resource (ARes) connects business objects and Representational State Transfer (REST) web services. It implements object-relational mapping for REST webservices to provide transparent proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing in ActionController::Resources).
Active Resource attempts to provide a coherent wrapper object-relational mapping for REST web services.
Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database tables. When a request is made to a remote resource, a REST XML request is generated, transmitted, and the result received and serialized into a usable Ruby object.
What’s wrong with this?
From the image below, we can assume that we will map our product model directly to our resource and that ActiveResource will do the work nicely.
What about this?
Are all the representations of our resources mapping directly to our ActiveRecord models?
We are tempted to create a dashboard model in our application and have it represent the state of several objects in our system. But is ActiveResource the best way to represent our REST documents? How easy is it to compose a representation with several objects mixing ActiveRecord, Mongodb, Riak, etc?
Based on REST we are consuming documents representing the state of some part of our application.
Using ActiveResource, we still have to compute hyperlinks to get the ActiveRecord mapped objects into our front end. But what if the document provides the hypermedia links to the other associated representations?
ActiveResource is not web oriented. The missing feature: Hypermedia
To represent hypermedia Roar provides HAL. It’s not mandatory to use it, but I suggest you consider it if you want to use hypermedia documents.
HAL is a lean, domain-agnostic hypermedia type in both JSON and XML, and is designed specifically for exposing RESTful hypermedia APIs.
HAL has two main components: resources and links. Resources have their own state, links, and embedded resources (which are resources in their own right)
Roar to the Rescue
Resource-Oriented Architectures in Ruby. “Lets make documents suit our models and not models fit to documents.” Please note that Roar is still in conception, the API might change as well as concepts do.
Central to Roar are representers – object-oriented documents suitable for parsing and rendering, extendable at run time and with hypermedia support. The representer concept is the answer to the missing REST abstraction layer in most frameworks.
- OOP access to documents
- Parsing and rendering of representations in one place
- Declaratively define document syntax and semantics
- Hypermedia support
- ActiveResource-like client support
- Useable in both client and server
- Framework agnostic, runs with sinatra, Rails, webmachine and friends
Considering that we have a REST API back end for our application, this is how it would look without Roar:
By adding Roar:
And here’s how it will look in code:
# dashboard.rb in the backend # Dashboard is not ActiveRecord, is a Ruby object. # class Dashboard include DashboardRepresenter attr_reader :user def initialize(id) @user = User.find(id) end def user_id @user.id end def galleries(limit = 5) @user.galleries.limit(limit) end end # dashboard_client.rb in the client # we use dashboard_client to have the representation of the Dashboard # remote object. # require 'roar/representer/feature/client' class DashboardClient include ::Roar::Representer::Feature::HttpVerbs def initialize extend(DashboardRepresenter) extend ::Roar::Representer::Feature::Client end end # dashboard_representer.rb shared between backend and client # this code can be shared between client and server to get # the same representation and share some behavior. # I think is a good idea to put them on a gem and include the # gem in both applications # require 'roar/representer/json/hal' module DashboardRepresenter include ::Roar::Representer::JSON include ::Roar::Representer::JSON::HAL::Links include ::Roar::Representer::Feature::Hypermedia property :user_id collection :galleries, extend: GalleryRepresenter link :self do 'http://self' end end # gallery_representer.rb shared between backend and client module GalleryRepresenter include ::Roar::Representer::JSON property :id property :name end # users_controller.rb on the backend responding to dashboard # the controller will know how to respond to the request as # the Json representation. # class UsersController < ApplicationController respond_to :json responders Roar::Rails::Responder def dashboard dashboard = Dashboard.new(params[:user_id]) respond_with(dashboard) end end
We share the representers in client and server as mixins.
Is not required to use Roar on both sides, but the fact you can gives it an advantage over ActiveResource. The representers also can be seen as a contract between the client as server or interfaces in Java.
Web development is a lot more distributed than it’s ever been, so we need to design distributed systems more often. Distributed systems are more complex and include more variables. The removal of ActiveResource as a default integrator forces us to start looking for alternatives. Roar is more than a replacement: It provides a missing layer to get pure Ruby object representations of our resources.
How about you? Any tips? Tell me by posting a comment below.