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?