New complex AR object saves - how is tree traversed?

If I have a new (new_record? == true) AR::Base descendant at the root
node of a complex object tree, and I call save on it, I expect that the
save will cascade down to each object in the tree.

  1. Is this true? Does the save cascade all the way down the tree?

  2. If so, in which order will the cascading save occur (bottom up from
    the leaves or top down from the root)?

  3. Here’s a specific problem that I’m seeing:

Assume that the graph looks like A -> B -> C
A is the root, A has_one B, and B has_one C.
B happens to have other attributes that aren’t shown.

I update various attributes from my form and then call a.save.

EXPECTED RESULTS: That A and B will fail validation, and that C will
pass, and I will see the related error messages. Nothing will be saved,
because I am in a transaction and I call rollback_db_transaction
explicitly if I detect any error arrays on A, B, or C that have size > 0
(since A and B should have non-empty error arrays).

ACTUAL RESULTS:
Validation runs for A and I see its error messages.
Validation does NOT run for B and I don’t see its error messages (but I
assure you that B is invalid based on the data).
A and B (and B’s non-C subordinate objects) are not saved, but C is
saved.

WTF? Why does C save - I’m in a freakin’ transaction, supposedly, and I
rolled it back! It looks to me like the transaction block, well,
doesn’t really work. Should I expect that calling
rollback_db_transaction will cause all of the DB activity to rollback or
not?

Thanks,
Wes

P. S. In the meantime, I’m going to go ahead and do the validation by
hand and then control saving based on getting past the validation
successfully.

OK, forget this post.

I discovered that I have misunderstood the update_attributes method for
a long time and didn’t realize that it did an implicit save, which
explains why my “C” object was being saved.

Thanks,
Wes