One of the challenges we face working with REST ORMs is that only a few have a built in concept of per user or per request authorization - authorization to the API tends to be global in scope. In our use cases, we authorize as the user to the remote API and so need to scope authorization on a per instance / request basis. One of the ways we've worked around this with ActiveResource is exposing the concept of an authorization object that is passed on object initialization:
Cartridge.new :name => 'foo', :as => current_user
and then making sure that the appropriate remote calls in ActiveResource introspect the model object for the presence of that "as" object in order to build HTTP headers for the response (either BASIC or API token, as necessary). The :as object in this case exposes either to_headers or :user, :password / :to_api_token depending on what makes sense. In ActiveResource this is a fair amount of pain.
As I was looking at Her I liked that most API requests passed through an API object that could be scoped, although in many cases the scope was at the class level. From a pure architectural level, are you opposed to the idea that a Her API object might have a local scope (on an instance) or a global scope (on a model object) and that the instance would delegate up the chain to locate that object before making a new request? One implication with that is that new() and find() methods would need to properly inject the correct API object to factory created methods, but that did not seem insurmountable. The goal would be to allow a model to parameterize the HTTP requests it makes to the remote endpoint - I was working from the assumption that the cleanest way to do that would be to allow a model object to add middleware to the parent API object (thus specializing the call).
I took a rough stab at a branch to demonstrate the concept - https://github.com/smarterclayton/her/compare/experimental_api_scoping, with a Gist demonstrating mixing in of the API (https://gist.github.com/3361943). Some of the changes in the gist would also need to be in Her but the idea would be that specialization of an api object would be possible through any Her descended model class or instance. In this case it's demonstrating a mixin that looks for :as on the instance and adds a custom faraday middleware to requests that come from that instance.
A usage example is:
api = Her::API.new
api.setup :base_uri => "http://localhost" do |builder|
...
builder.use Faraday::Adapter::NetHttp
end
class Model
include Her::Model
include ConsoleModel::WithAuthorization
authorizes :with => ConsoleModel::Middleware::Authorizes
uses_api api
end
model = Model.new :as => User.new('bob', 'password'), .... # other attributes
model.save # the presence of :as triggers api specialization such that the middleware
# or alternatively, if you prefer specialization of the model class
model = Model.as(User.new('bob', 'password').new #other attributes
model.save
Authorization is one example where this sort of middleware approach might make sense - model level caching mixins is possibly another:
model = Model.cached(:for => 5.min).find('by_id')
Would you be opposed to a pull request exploring the minimal changes necessary to support an inheritance chain for API objects (allowing an instance to delegate to the class, which could delegate to its parent class, etc) and the support for specializing those objects? Is model specialization via class/eigenclass/instance inheritance something you've previously considered for Her?