ActiveRecord's design allowing silent failure of object saves in associations

I take issue with the faxt that in some cases ActiveRecord may
automatically
save records using “save” rather than “save!”. Specifically, this is
when
assigning an object to a “has_one” relation, or adding an object to the
collection vreated by the remaining “has_*” associations.

The automatic saving alone seems a bit questionable to me, but I’ll
cover
that second. The fact that it uses “save” rather than “save!” is a
bigger
problem.

Let me take the example a a “Bar” class that “has_one :foo”. If i use
Bar#foo=, if the foo fails validation I get a silent failure.

The only way to check for failure is to check for the return value of
the
assignment. That is really ugly. First of all that is very unexpected.
Nobody whould ever just guess that one needs to check the return value
of an
assignment. Further the idiom of checking the return value of an
assignment
already exists in other languages where it is largly just a shorthand.
So
people familar with other languages would misinterpet the code.

It is also a very easy idiom to forget. People are very accustomed to
assignments never failing without throwing an exception. Overall this
whole
thing severly violates the priciple of least surprise.

There is a similar case with the remainin has_* associations, but the
problem is slightly less severe there, as at least the idioms needed
(checking the return value of << or of Baz#foos.push, etc) are less
surprising. But it is still easy to forget to check in the first place.

I would really like it if there were some way to request that “save!” be
used in place of “save” in these locations. I’m not sure how best to
expose
such an option, since existing code that expects the current behavior
would
broken by such a change. (Although I suspect there is much more code
that is
currenly silently failing to save in some cases, where throwing an
exception
would help to higlight the brokeness of the code.)

But I’m not entirely convinced that saving immediately is the correct
thing
to do. Why not just delay the saving until the object with the “has_"
association is also saved? The code nessisary to do so already exists
because that is absolutely required in the case that the object with the
"has_
” association is a new record. So why not just do that in all
cases?

Am I just missing something here?