Why assign site in ActiveResource?
posted by andy, Tue Apr 22 16:30:00 UTC 2008
ActiveResource is a great tool for helping your business keep not only its business logic DRY, but even keep its business applications dry. If you're not familiar with ActiveResource, think of ActiveRecord using an internet-based datastore. It's a bit more complicated than that but you can do all the basic CRUD methods, custom methods, etc
The advantage that ActiveResource brings, though, is that you only need to create the object once. Ever. Used effectively, you don't need to create an object in one project that you import or somehow reuse in another. You create a small, targetted application and share the application with other applications. For example, you could create an accounting engine that deals with ledgers and accounts and journals and expose the RESTful HTTP interface to higher level apps that simply consume the Journals and Ledgers and Accounts using ActiveResource. Within a single company it might be the ultimate in DRY.
For Rails developers, ActiveResource is very clearly modeled on ActiveRecord. If you've gotten used to one set of methods you should almost seamlessly be used to the other. With one painful exception: setting the site in the class. I honestly cannot understand why there is no configuration yaml equivalent to database.yml for ActiveResource. Maybe it was unnecessary since the creators already had some RESTful applications with which to work. Whatever the case, it's a real pain in the neck.
In an attempt to keep the ActiveRecord-like API going, I've come up with the following code that I've been dropping in /lib/core_ext/active_resource.rb
require 'yaml'
class ActiveResource::Base
protected
def self.establish_site_connection(site_id)
site_yaml = File.new(File.join(RAILS_ROOT, 'config', 'sites.yml'))
environment_configurations = YAML.load site_yaml
site_configurations = environment_configurations[RAILS_ENV]
return site_configurations[site_id.to_s]
end
end
The code is supposed to emulate ActiveRecord.establish_database_connection. As implemented above it will add an establish_site_connection method to your ActiveResource class that will read a sites.yml file in your /config folder. sites.yml is structured similarly to database.yml -- you have entries for each environment (development, test, production, etc) along with site names and urls for each site.
development:
activity_center: http://localhost:3002/
church_member: http://localhost:3001/
test:
activity_center: http://testy:3002/
church_member: http://testy:3001/
With such a configuration file, of course, you have a few luxuries. First, you can use different sites while running in different environments. This might make it easier, for example, to create mocks for testing ActiveResource objects. Second, you can more quickly adapt to external changes (e.g., remote resource down or relocated) since it's just a yaml change and not a source code change.
I've typically gone one step further with the ActiveResource hack. As alluded to above, I have sites split into separate sub-applications each responsible for part of the end solution. As a result I have a whole family of ActiveResources that use one source application. For this reason I have emulated the multiple database solution for Rails with the following for ActiveResource.
require File.join(RAILS_ROOT, 'lib', 'core_ext', 'active_resource_extension')
class ActivityCenterResource < ActiveResource::Base
# see /lib/core_ext/active_resource_extensison.rb
self.site = self.establish_site_connection(:activity_center)
end
class ActivityCenter < ActivityCenterResource
...
end