Reputation: 21795
When receiving:
{
parent:{
children_attributes:[
{child1}, {child2}
]
}
}
And child1
instance is about to be created, I don't have parent_id
set. I suppose this is set in save time.
How can I handle this to say something like:
class Child < ActiveRecord::Base
belongs_to :parent
before_save :do_something
def do_something
# access parent here
# I can't, since parent_id is nil yet
end
end
class Parent < ActiveRecord::Base
has_many :children
accepts_nested_attributes_for :children
end
I tried this from related questions:
class Parent < ActiveRecord::Base
has_many :children, inverse_of: :parent
end
But same issue.
I tried this
class Parent
before_save :save_children
attr_accessor :children_attributes
def save_children
children_attributes.all? do |k, attrs|
# tried different things here, this one is the one I expected to work the most
child = Child.new attrs.merge(parent_id: id)
child.save
end
end
I added parent_id to child attr_accessible call.
What am I missing?
Upvotes: 3
Views: 2470
Reputation: 414
I think the best way to handle this is to override the child_attributes(attributes)
method added to the parent model.
https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
You can set the parent association on the child here
def child_attributes(attributes)
self.child = Child.new(attributes.merge(parent: self))
end
This allows you to reference the parent from the child on new
Upvotes: 0
Reputation: 321
The cause of this problem for me was the validation of the presence of the parent in the child class.
I essentially removed this line from the Child object and it works.
validates :parent, presence: true
From what I've found, however, the correct way to resolve this is the use of the inverse_of
parameter. If you add this to the has_many
of the parent and the belongs_to
of the child, you should be good to go.
In the parent:
has_many :child, inverse_of: :parent
In the child:
belongs_to :parent, inverse_of: :child
Upvotes: 2
Reputation: 1358
Set inverse_of: :model_name
in has_many declaration in your model where model_name is your 'parent' model.
For example: has_many :product_items, dependent: :destroy, inverse_of: :product
Upvotes: 1
Reputation: 180
This may or may not help with your issue: http://guides.rubyonrails.org/association_basics.html#association-callbacks
Association callbacks don't work with belongs_to
, but does work well with has_many
.
class Parent < ActiveRecord::Base
has_many :children, before_add: :do_something
def do_something(child)
# self.id = 1
# child.parent_id = 1
end
end
# parent1 = Parent.find(1)
# parent1.children.create(...)
Upvotes: 0
Reputation: 530
In your model, you should be able to reference the parent like this:
self.parent_class
So for example, if a product have many parts, in your parts model (part.rb) you can refer to an attribute of the product like this:
self.product.id
That would return the id of the product that is the parent of the part. You can obviously reference any attribute of the parent like this.
This should work in your before_save callback in the child model.
Also, you shouldn't need the "inverse_of: :parent" that you included in your code above for this to work.
And to answer your question about when the parent id is added, that should be automatically passed in the params from your form to your controller if your form is set up correctly.
Upvotes: 0