views:

170

answers:

2

Consider the following setup:

class Parent < ActiveRecord::Base
  has_many :children
end

class Child < ActiveRecord::Base
  belongs_to :parent
end

And this console session:

>> p = Parent.find 41
>> p.some_attr = 'some_value'
>> c = p.children.build
>> c.parent

By watching my log files, I can see that c.parent is querying the db for the parent object. I want instead to access the existing in-memory object (p), because I need access to the parent's some_attr value, which is not yet stored in the database. Is there any way of doing this? c.parent(force_reload=false) doesn't get me there.

+1  A: 

ActiveRecord doesn't endeavor to guarantee that in-memory objects for the same database objects are all the same. This is something that DataMapper does guarantee.

I realize your example is probably simplified in order to ask your question, but just from a naive look at it -- why don't you just use p instead of c.parent?

Another possibly helpful suggestion, save the update to parent to the db:

p = Parent.find 41

# do this...
p.some_attr = 'some_value'
p.save

# OR this...
p.update_attribute(:some_attr, 'some_value')

c = p.children.build
c.parent

I'm not sure if c.parent(false) ("don't reload from the db") will do the trick here, since it's a fresh Child object. But you can try that too.

John
You are right about the example being simplified - in real life I am working with a validation scenario in which the child's validity depends on attributes of the parent (actually, attributes of a sibling object collection). So in the child object's validation code I need to get to the parent as it exists in memory, with all of the attributes that just got assigned/updated when the html form was submitted, and not the stale version that is sitting out in the db. I am using accepts_nested_attributes_for :children, so I know everything is set up as I need it in memory.
You can do the whole thing in a transaction -- that way you can save the parent, then check the validation, if validation fails, you roll back.
John
A: 

You could use :inverse_of to set it. Read more about it here.

YonahW
Yes, :inverse_of was developed precisely to fit this need.