this is a followup to my question here: Updating child association in ActiveModel
i'm looking for the standard/correct way to update a number of children records associated with a parent.
lets say i have a parent (connected to a child table with has_many, and :autosave=>true).
obj = Parent.first
now i iterate over its children, and update them.
obj.each.do |child|
child.remark = "something"
end
i would like the children to be saved with the parent, when calling obj.save, but as explained to me in the previous question, the only way to do it is to update it directly, like this:
obj.children.first.remark = "something"
(or save each child, but this will require an explicit transaction which i believe shouldn't be used here).
what is the correct way to implement this?
thanks!
*edit : following the advice given here, i've added this to the model:
class Parent < ActiveRecord::Base
has_many :children, :inverse_of => :parent,:autosave=>true
accepts_nested_attributes_for :children
But still,
x = Parent.first
c = x.children.first
c.remark = "something"
x.save # => doesn't update c
You want ActiveRecord nested_attributes
class Parent
include ActiveModel::Model
accepts_nested_attributes_for :children
end
Update your children and save the parent, you should be done
EDIT: you have to call parent.children
first:
irb(main):001:0> x = Parent.first
Parent Load (0.3ms) SELECT "parents".* FROM "parents" ORDER BY "parents"."id" ASC LIMIT 1
=> #<Parent id: 1, created_at: "2013-08-07 21:21:10", updated_at: "2013-08-07 21:21:10">
irb(main):002:0> x.children
Child Load (3.0ms) SELECT "children".* FROM "children" WHERE "children"."parent_id" = ? [["parent_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy [ ]>
irb(main):003:0> x.children.first.remark = "foo"
=> "foo"
irb(main):004:0> x.save
(0.3ms) begin transaction
SQL (2.3ms) UPDATE "children" SET "remark" = ?, "updated_at" = ? WHERE "children"."id" = 1 [["remark", "foo"], ["updated_at", Wed, 07 Aug 2013 21:33:04 UTC +00:00]]
(0.3ms) commit transaction
=> true
You could overwrite the save method but I would not do that. Why not do something like this?
def save_with_children
Child.transaction do
children.each do |child|
if child.changed?
child.save
end
end
end
save
end
This should run 1 query. Probably wouldn't work if you had 10'000'000 records but you didn't mention that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With