save! fails silently

Pedro Côrte-Real wrote:

I have a model class that has these associations

class Description < ActiveRecord::Base   belongs_to :description   belongs_to :cluster

and this check rule:

  validates_presence_of :cluster_id

Did you intend "validates_presence_of :cluster"?

The description association is an association to itself to do parent/child relationships.

If I do something like

d1 = Description.new d2 = Description.new d2.description = d1 d2.cluster = ...find a cluster... d2.save! d1.cluster = ...find a cluster... d1.save!

the association isn't saved but save! doesn't fail. If instead I do:

Could you more fully explain what you were expecting and what actually happened.

Did you intend "validates_presence_of :cluster"?

From the docs:

""" Validate the presence of the foreign key, not the instance variable itself. Do this:

validate_presence_of :invoice_id

Not this:

validate_presence_of :invoice

If you validate the presence of the associated object, you will get failures on saves when both the parent object and the child object are new. """

> The description association is an association to itself to do > parent/child relationships. > > If I do something like > > d1 = Description.new > d2 = Description.new > d2.description = d1 > d2.cluster = ...find a cluster... > d2.save! > d1.cluster = ...find a cluster... > d1.save! > > the association isn't saved but save! doesn't fail. If instead I do:

Could you more fully explain what you were expecting and what actually happened.

I created two descriptions (d1 and d2). I set the parent of d2 to be d1. Then I saved each of them. The result was that d1 is not set in the database as the parent of d2.

> d1 = Description.new > d2 = Description.new > d2.description = d1 > d2.cluster = ...find a cluster... > d1.cluster = ...find a cluster... > d2.save! > d1.save!

In this case it works because when I go to save d2 I've filled d1 as well and it is now valid. In this case in the database d1 is set as the parent of d2.

I understand why this happens, that the first option doesn't work because d1 isn't valid when I try to save d2. What I would expect is for the save to fail in this case, instead of silently ignore the association and leaving me with two broken records that don't have a link between them.

Pedro.

Pedro Côrte-Real wrote:

Did you intend "validates_presence_of :cluster"?

From the docs:

""" Validate the presence of the foreign key, not the instance variable itself. Do this:

validate_presence_of :invoice_id

Not this:

validate_presence_of :invoice

If you validate the presence of the associated object, you will get failures on saves when both the parent object and the child object are new. """

To my thinking this advice is wrong. It's the associated object that can be made non-nil before saving, thus allowing validation to pass, while for new records the foreign key won't be set until after saving, so will either always fail validation (if the default column value is null) or always pass validation (if the default column value is 0).

I understand why this happens, that the first option doesn't work because d1 isn't valid when I try to save d2. What I would expect is for the save to fail in this case, instead of silently ignore the association and leaving me with two broken records that don't have a link between them.

Yes, I would regard this as a bug in saving belongs_to associations because a failed automatic save of the associate is not signalled to the original save. Specifically, the before_save callback in which the associate is saved should be returning false if this save returns false. This requires patching of the belongs_to method in active_record/associations.rb.

A work-around would be to add "validates_associated :description" to your Description model.