More on Object Graphs in Active Record

As I said in my last post, I can't help but to think there is a better way to persist object graphs in Rails applications. The solution I outlined last time seems to stray from the DRY principle (Don't Repeat Yourself,) and just seems to leave a bad taste in my mouth. Don't you wish there was some way to leverage the meta-programming capabilities of Ruby and Rails to solve this problem in a generic way? Me too. Consider the following sketch of a solution:

def update_object_graph(root_entity, entities_seen = [])
  # return if we've processed this entity already
  return if entities_seen.include?(root_entity)
  entities_seen << root_entity
  errors = []

  parameter_name =
  # if paramaters are given for the root entity, then we update it
  if params[parameter_name]
    keys = params[parameter_name].keys
    index = keys.index(
    root_entity.attributes = params[parameter_name].values[index]
    errors += root_entity.errors.full_messages unless
  forward_associations =
    root_entity.class.reflect_on_all_associations -

  forward_associations.each do |association|
    # ignore acts_as_versioned association tables
    next if(/::Version$/ =~ association.class_name)
    raise unless root_entity.respond_to?(
    # Deal with has_one associations
    if(association.macro == :has_one)
      assoc_entity = root_entity.send(
      new_errors = update_object_graph(assoc_entity, entities_seen)
      errors = errors + new_errors if new_errors
      # Deal with has_many and habtm associations
      association_entities = root_entity.send(
      association_entities.each do |assoc_entity|
        new_errors = update_object_graph(assoc_entity, entities_seen)
        errors = errors + new_errors if new_errors

The idea here is that we first update the current entity with any corresponding values in the parameters hash. Then we attempt to save the entity and collect any errors. Remember, since the save method is called on the actual instance of the entity in question, it's erorrs collection will be populated and used when rendering the page. Now things get interesting - we discover the associations of the entity, and then use reflection to obtain references to the actual objects that represent those associations. Now we recursively call persist_object_graph on each of these objects.

Makes perfect sense right? Let me first say that this code doesn't actually work: it is just a sketch of a solution and has lots of oversights (no support for composed_of aggregations, it makes assumptions about the names of things, etc.) However, I was hopeful that I could take this idea and run with it. Unfortunately, this solution hits a brick wall when we back up and take a real close look at the Active Record design pattern. Can anyone spot the subtle but major flaw here?

blog comments powered by Disqus