views:

175

answers:

1

I'm working with some models where a lot of a given model's key attributes are actually stored in a submodel.

Example:

class WikiArticle
  has_many :revisions
  has_one :current_revision, :class_name => "Revision", :order => "created_at DESC"
end
class Revision
  has_one :wiki_article
end

The Revision class has a ton of database fields, and the WikiArticle has very few. However, I often have to access a Revision's fields from the context of a WikiArticle. The most important case of this is probably on creating an article. I've been doing that with lots of methods that look like this, one for each field:

def description
  if @description
    @description
  elsif current_revision
    current_revision.description
  else
    ""
  end  
end
def description=(string)
  @description = string
end

And then on my save, I save @description into a new revision.

This whole thing reminds me a lot of attr_accessor, only it doesn't seem like I can get attr_accessor to do what I need. How can I define an attr_submodel_accessor such that I could just give field names and have it automatically create all those methods the way attr_accessor does?

+4  A: 

The term "submodel" threw me off because it's nonstandard terminology, but I think what you're looking for is delegate. Basically it lets you delegate certain method calls to a property or instance method of an object.

In this case you would do something like this:

class WikiArticle
  has_many :revisions
  has_one :current_revision, :class_name => "Revision", :order => "created_at DESC"

  delegate :description, :to => :current_revision
end

You can do this for as many methods as you want, e.g.:

delegate :description, :title, :author, :to => :current_revision
Jordan
Thanks for this, I hadn't heard of the delegate method before. For anyone else that reads this, note that delegate requires you to separately delegate the '=' method of a field as well. Unfortunately, the delegate method isn't quite versatile enough to do what I was doing in my example, where the parent model temporarily holds fields for child models before creating them on save. Incidentally, what is the standard terminology for submodels?
WIlliam Jones