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.