validates_presence_of :parent_id stopping save

Hi. I'm using rails 2.3.4 and have this association between two of my models.

Question   has_many :gradings

Grading   belongs_to :question

Grading has this validation:   validates_presence_of :question_id

And this validation test is stopping me from doingg this, which i would normally expect to work

@question = Question.new(attributes) @grading = @question.gradings.build(more_attributes) @question.save #fails because grading has no question_id

Now, i thought that this would work ok because (in my understanding) the question is saved and then it saves it's built associated objects. How can i ensure this will work? Do i need to drop the validation? I'd rather not if possible.

Grateful for any advice - max

Hi,

I’m not sure 100% what you’re trying to do but the presence of question_id will not be there until the record has been saved. No?

And I’m not sure why you’re doing this … @grading = @question.gradings.build(more_attributes)

Shouldn’t you have done a build before presenting your form if you have nested forms?

Maybe you could teach me something on what you’re trying to do.

I'd say the best way to deal with this is never validate for a association_id

#validates_presence_of :question_id validates_presence_of :question

would be better.

if grading.question_id is nil then grading.question will also be nil. So you're effectively doing the same check.

I hope this helps

RobL

Rob Lacey wrote:

I'd say the best way to deal with this is never validate for a association_id

#validates_presence_of :question_id validates_presence_of :question

would be better.

Hi Rob!

I played with this already, and got a surprising result:

@question = Question.new(attributes)

=><a question>

@grading = @question.gradings.build(other_attributes)

=><a grading>

@grading.question

=>nil

This surprised me because i thought that the use of build set up the association both ways, ie in both objects, so that even though @grading had no question_id it 'knew' that it was associated with @question. I must admit that this aspect of rails (ie associations that have been built but not saved yet) is something that i've always found a bit magical and hence unpredicatable.

Hi Anthony, thanks.

I'm not using the rails-supplied nested attributes methods here, though maybe i should. I'm effectively hand-rolling my own, so i create a question and some associated objects (eg a grading in this case) at the same time, from a single form. When i drop the validation on Grading#question_id then it works fine. I'm just a little puzzled about the best way to go about validating question_id, since the default way seems to stop me building a question and gradings at once.

I don’t have your original mail and am not sure of the model but question_id is a foreign key.No? You are checking for the existence of it before it has been created, that is why it’s failing, no?

validate methods validate the data before its saved. Unless I’m missing something from your original query.

Also, build will only build the object without saving it.

So I think you are thinking something should be happening when it’s not.

But I’m quite new to ruby/rails and although I’m developing an application and trying to learn at the same time, it’s difficult to grab all the nuances of Rails. There’s a lot to learn to become proficient.

Hi Max,

Have you tried:

@question = Question.create(attributes) @grading = @question.gradings.build(more_attrs)

Using create instead of new will save the Object to the DB first, and hence:

@question[:id] will/should/may not be nil when building your gradings.

I'm six months in to Rails, don't use build, and haven't needed to use any validation yet - am currently extending the generator for my current and future Apps, so I have held fire on my first app until I get this completed, but if your only issue is that the FK question_id requires @question[:id] to exist, then unless I'm mistaken(which I could be), using create over new should work.......

HTH

Paul

paul h wrote:

Hi Max,

Have you tried:

@question = Question.create(attributes) @grading = @question.gradings.build(more_attrs)

Using create instead of new will save the Object to the DB first, and hence:

Hi Paul. Yes, i know that, thanks - in this situation i would do gradings.create rather than gradings.build. One of the advantages, though, of using build is that you can do it before the parent has been saved, and when the parent is saved it will save the child as well.

In general, i try to stick to the standard controller code as much as possible, which means setting the child gradings through a set method which will be called by .update_attributes. This is a nice approach as it means no changes to the standard controller code is required. When i drop the validation on Grading#question_id (or Grading#question) then it works fine. My question was really about the behaviour of the unsaved child objects, and whether they 'know' they have a parent. It seems they don't.