Rails is great and most things just work easily. However, I've never
been able to get a definite answer on whether one should do,
validates :parent, :presence => true
or,
validates :parent_id, :presence => true
given,
class Parent
end
class Child
belongs_to :parent
end
I've always thought that validating the :parent (and not the foreign
key) is the *more* correct thing to do ... but I don't understand why
Rails does not reset the parent association when the parent_id is
changed as demonstrated here,
I've always thought that validating the :parent (and not the foreign
key) is the *more* correct thing to do ... but I don't understand why
Rails does not reset the parent association when the parent_id is
changed as demonstrated here,
This is due to the way that association proxies lazy load their targets. In the first case, if you only loaded the child record, and modified the parent_id attribute, then you never load the parent object, because you never accessed the association proxy.
In the latter case, you did access the association proxy, so the parent got loaded, but then you modified the parent_id, directly. I'd recommend that you be consistent -- if you're checking if the associated object exists, set the association to nil, instead of the id, and you shouldn't have a problem.
In edge rails there is a mechanism for checking whether the loaded
association target is "stale" - so if you do record.foo_id = x, then
record.foo will load the target afresh.
I'm not sure whether it necessarily works with validation like this, but
hopefully it does. [I haven't tried.]
Just to emphasise, this is new in edge - it is not in the 3-0-stable
branch.
Sure ... sometimes the parent_id though is passed via form params.
Which works in 99% cases, however, I had one or two cases where
something loaded the parent before setting parent_id and
validating :).
Rails is great and most things just work easily. However, I've never
been able to get a definite answer on whether one should do,
validates :parent, :presence => true
or,
validates :parent_id, :presence => true
Validate the object, not the foreign key. Otherwise a record with
parent_id of -99, 0 or some other nonsense will still pass.
given,
class Parent
end
class Child
belongs_to :parent
end
I've always thought that validating the :parent (and not the foreign
key) is the *more* correct thing to do ... but I don't understand why
Rails does not reset the parent association when the parent_id is
changed as demonstrated here,
As Jon mentioned there is some code for this kind of thing in master.
As for the historical reason it did that, it's trickier than it looks
There can be multiple (or zero) associations for a given _id column,
and a patch we tried a while back didn't handle all those potential
cases. There's no deep philosophical reason it works that way, it's
just historical / evolutionary artifacts sneaking up on you.
Unfortunately the Rails Guide on Active Record Validation and
Callbacks says (Section 3.9):
"If you want to be sure that an association is present, you’ll need to
test whether the foreign key used to map the association is present,
and not the associated object itself."
Yeah, I think the wording is unfortunate. Certainly you can't be sure
the association is present by checking that the FK attribute is
present.
Rather, this topic deserves a warning in my view. Something in the
line that if you check whether the FK attribute is present then you
*don't know* whether it is valid. You can decide to take the risk,
that's up to you, but the reader should be warned.
A pointer to the validates_existence plugin would be nice. Also to FK
constraints as the most robust solution, though they are kinda weird
to explain in a generic way nowadays because then #save,
#update_attributes and friends can throw exceptions for ordinary
validation errors, and that doesn't fit well with standard idioms.
This would deserve its own section in the guide with all practicals
details and gotchas.
If you'd like to have a stab at any of these revisions please give it
a go through docrails.
Unfortunately the Rails Guide on Active Record Validation and
Callbacks says (Section 3.9):
"If you want to be sure that an association is present, you’ll need to
test whether the foreign key used to map the association is present,
and not the associated object itself."
Maybe the guide needs to be updated.
Yeah, I think the wording is unfortunate. Certainly you can't be sure
the association is present by checking that the FK attribute is
present.
Rather, this topic deserves a warning in my view. Something in the
line that if you check whether the FK attribute is present then you
*don't know* whether it is valid. You can decide to take the risk,
that's up to you, but the reader should be warned.
But this thread seems to suggest one should simply validate the
association attribute instead. Is that not sufficient then?
If you'd like to have a stab at any of these revisions please give it
a go through docrails.
I'd say validating the association attribute would be the best practice
in 3.1, but it may result in an extra query to the database to fetch the
associated record, if it's not loaded or if it's stale.
If users wish to avoid that overhead, they can check the FK, but should
be aware that this does not guarantee the associated record actually
exists.
You're going to store the post_id in the database anyway. So if you're
going to take the risk of having dangling records, in my view it's
better to take the risk on the post_id rather than on the association.
I believe that's what the quote from the guide tries to say.
The validates_existence plugin performs a query. That's closer to
checking the association holds an existing record, but there's still
subject to race conditions (say, a concurrent request deleting the
associated record outside your transaction). The only way to be
totally sure the association does exist is to move the check to who
has the key to guarantee that, which is the database with FK
constraints.