How to automatically assign parent ID as foreign key when using nested attributes?

158 Views Asked by At

An action creates records based on multiple layers of nested attributes, upon the submission of a form. However, the ID of the root record, which I call .save on, is not propagating downwards to the associations.

Here's a simplified example:

class A
  has_many :bs
  # Note that A has direct access to C, without going through B
  has_many :cs
  accepts_nested_attributes_for :b
end

class B
  # B has an :a_id field
  belongs_to :a
  has_many :cs
  accepts_nested_attributes_for :c
end

class C
  # note that C has a "circular relationship" to A, 
  # either directly through the :a_id field, or indirectly through B
  belongs_to :a
  belongs_to :b
end

Given the model definitions above, this is an example payload:

{
  a: {
    name: "Model A",
    bs_attributes: [{
      name: "Model B",
      cs_attributes: [{
        name: "Model C"
      }]
    }]
  }
}

And this payload will be fed into:

A.create(payload)

When that gets persisted on the database and A is assigned an ID, I expect this ID to be automatically set as a foreign key on both children (B) and grand-children (C) records. Is that something that can be accomplished using Rails built-in functions, with simple effort?

An example of solution I could think of would be adding a before_save callback on associations to manually set the :a_id field. However this feels like it could be accomplished in simpler ways.

Currently working on Rails 5 but any guidance is appreciated.

1

There are 1 best solutions below

0
Arctodus On BEST ANSWER

Using inverse_of to link the associations should work for the nested attributes. Example, A to B:

class A
  has_many :bs, inverse_of: :a
  accepts_nested_attributes_for :b
end

class B
  belongs_to :a, inverse_of: :bs
end

Same thing for C to B.

A to C is a bit special. Setting c.a = b.a in before_validation callback on C is an option.