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