views:

177

answers:

2

Suppose we have the standard Post & Comment models, with Post having accepts_nested_attributes_for :commments and :autosave => true set.

We can create a new post together with some new comments, e.g.:

@post = Post.new :subject => 'foo'
@post.comments.build :text => 'bar'
@post.comments.first # returns the new comment 'bar'
@post.comments.first.post # returns nil :(
@post.save # saves both post and comments simultaneously, in a transaction etc
@post.comments.first # returns the comment 'bar'
@post.comments.first.post # returns the post 'foo'

However, I need to be able to distinguish from within Comment (e.g. from its before_save or validation functions) between

  1. this comment is not attached to a post (which is invalid)
  2. this comment is attached to an unsaved post (which is valid)

Unfortunately, merely calling self.post from Comment doesn't work, because per above, it returns nil until after save happens. In a callback of course, I don't (and shouldn't) have access to @post, only to self of the comment in question.

So: how can I access the parent model of a new record's nested associations, from the perspective of that nested association model?

(FWIW, the actual sample I'm using this with allows people to create a naked "comment" and will then automatically create a "post" to contain it if there isn't one already. I've simplified this example so it's not specific to my code in irrelevant ways.)

A: 

I don't think you can do this. On the other hand, your validations shouldn't be failing, as the order of the transaction will create the post record before saving the comment.

MattMcKnight
+2  A: 

I think it is strange that Rails does not let you do this. It also affects validations in the child model.

There's a ticket with much discussion and no resolution in the Rails bug tracker about this:

Nested attributes validations circular dependency

And a proposed resolution:

nested models: build should directly assign the parent

Basically, the deal is, the nested attributes code doesn't set the parent association in the child record.

There's some work-arounds mentioned in the second ticket I linked to.

Luke Francl
How would it do it? You don't want to set the parent_id column, so you'd have to add some hidden properties on the child?
MattMcKnight
You can set an attribute (e.g. parent, children) without setting the requisite _ids. That's how it does nested model saving currently - it just has this flaw of not being recursive.
Sai Emrys