WebObjects-style Object Cache

Hey Guys,

Here’s the scenario:

I have a model Page and every page has multiple page_parts. So,
there’s a form for editing a Page and all of it’s parts and when you
submit the form all of your changes are saved. There’s an action that
handles the post that saves the page and all the parts.

def handle_post
  if request.post?
    @page.attributes = params[:page]
    parts_to_update = []
    (params[:part] || {}).values.each do |v|
      if part = @page.parts.find_by_name(v[:name])
        part.attributes = part.attributes.merge(v)
        parts_to_update << part
      else
        @page.parts.build(v)
      end
    end
    if @page.save
      parts_to_update.each { |part| part.save }
    end
  end
  true
end

Pretty typical rails stuff right?
The line with “part.attributes.merge(v)” causes certain POST arguments
to be passed down to appropriate page_part objects and get populated
with the data our user filled out on the form.

So for instance here’s a method on page_part that gets called as a
result of a per page_part checkbox on the form: (when the checkbox is
checked value = true, otherwise value = false)

def is_template=(value)
super(value)
end

Now, let’s suppose there’s an attribute on the parent Page object that
we would like to update based on what happens in the page_part setter.

We might write:

def is_template=(value)
super(value)
self.page.has_template_page_parts = true if value
end

and you might also want to see a definition for page: (Not this is only
the definition I surmise is created automatically by the declaration:
“belongs_to :page”)

def page
Page.find_by_id(self.page_id).has_template_page_parts = true if
value
end

Do you see what I’m trying to do here? Do you see why this won’t work?

I want to be able to get the parent Page and set a value to one of it’s
attributes it, and then when the parent page saves that new value is
saved to the database.

The problem here, is that when we do “find_by_id” the Page object we
get is not exactly the same object as the one that we were saving in
“handle_post”. This is because Rails is doing a fresh select to find
the parent page, it doesn’t automatically know.

It would make sense to me, that it should automatically know based on
the way that “parts” is implemented in Page.

Here’s what “parts” looks like: (Note this is really what I surmise
parts looks like because it is generated by the fact that Page
“has_many :parts, :class_name => ‘PagePart’, :dependent => :destroy”)

def parts
PagePart.find(:all, :conditions => “page_id = #{self.id}”)
end

So, the find method creates an SQL query that find all the page_parts
that belong to this Page and returns them in a nice array. But, it
should KNOW that PagePart has an attribute page_id and thus an implicit
attribute called “page” which should be set with the Page object that
initiated the find. So when a Page objects is asked for all it’s
page_parts, the returned page_parts should return that very same Page
object when asked for their page.

I was looking for a way to access this implicit “page” object but
looking at the ActiveRecord source code I see no place that it would
have been set. This makes me believe my “it just works” assumption is
wrong in this case.

Does anybody have any idea what I’m talking about here?

In WebObjects, all my fetches to objects would go through an
EditingContext. So when I told my Page to fetch pageParts() then that
Page and all the PageParts would get plopped into one EditingContext.
And when I asked a PagePart for it’s Page, it would pull that object
from the EditingContext so I would get exactly the Page object I
expected instead of a fresh copy (or duplicate) Page object re-fetched
form the database.

Is there a name for the feature I am asking for here? Has anybody else
ever thought that this feature should exist in Rails? Has anybody
tried implementing it?

I have a very limited understanding of how “has_many :parts,
:class_name => ‘PagePart’, :dependent => :destroy” and “belongs_to
:page” leads to “page” being a working attribute of PagePart and pages
being a working attribute of Page. Perhaps if I better understood how
this works I might be able to add the behavior I’m expecting to see.

Please discuss!!

thanks,
Jacob