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.
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.
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.
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.......
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.