blog.ingoweiss.com

Fun with ResourceAwareness and ActiveResource

May 12, 2010 Ingo Weiss

In my last post (Resource Awareness), I introduced the resource_awareness gem and the thoughts behind it. In this post I would like to explore one interesting thing you can do with it, namely expose an application’s resources as a resource in turn which makes it very easy for other applications to dynamically create ActiveResource clients for interacting with those resources. Let me demonstrate:

Suppose you have an application with the following resources:

# config/routes.rb
resources :countries, :controller => 'countries' do
 resources :cities, :controller => 'country_cities'
end

Now let’s expose those resources like so:

# Gemfile
gem 'resource_awareness'

# config/routes.rb
resources :resources

# app/controllers/resources_controller.rb
respond_to :xml

def index
  respond_with Rails.application.resources
end

Information about the app’s resources is now available at /resources.xml. Now let’s start a server at port 3000 and fire up a console for another app to interact with the first app. First, we need an ActiveResource client to retrieve the first app’s resource information:

# console
> class RemoteResource < ActiveResource::Base; self.site = 'http://localhost:3000'; self.element_name = 'resource'; end
> RemoteResource.first.attributes
=> {"id"=>"country_cities", "path_prefix"=>"/countries/:country_id", "singular_name"=>"city", "path"=>"/countries/:country_id/cities", ...}

Turns out that two of the resource’s attributes, singular_name and path_prefix, is all we need to create an ActiveResource client for it. In most real world cases we would probably want to do this dynamically and would not want to create named classes blindly, so let’s use an anonymous ActiveResource subclass instead:

# console
> r = RemoteResource.first
> client_class = Class.new(ActiveResource::Base){self.site = "http://localhost:3000#{r.path_prefix}"; self.element_name = r.singular_name}
> client_class.create(:country_id => 1, :name => 'Berlin').attributes
=> {"name"=>"Berlin", "created_at"=>Wed May 05 10:51:31 UTC 2010, ... }

Just a fun experiment at first, this approach has already proven very useful in a current project of ours which I hope will be the topic of another post. I could also imagine this being useful in circumstances where you would otherwise use something more heavyweight such as WADL

blog comments powered by Disqus