Updating Child Records

I have a 3 level hierarchical data structure, for this example lets
say it’s Bike (has many) Wheels (has many) Spokes.

Here’s what I want to do, update a bunch of Spokes that all belong to
one Bike but do it all with one Save! method call.

I’ve tried loading the Bike, accessing, changing, and adding Spokes
through the Bike.wheels.spokes collections then doing Bike.save! but
it doesn’t work (the database remains unchanged). It DOES work
however when I create a new bike record, add the wheels and spokes
then save that.

So is there any way to have all the Spoke records saved with one call
to save? I’m attempting to limit the number of individual SQL calls,
cause there are a lot of spoke records and it will happen often.

Thanks in advance,
Danny

The problem with bike.wheels.spokes is because bike has many wheels, and
each wheel has many spokes. With bike.wheels.spokes, you’re trying to
call
spokes on the collection of all wheels for that bike, so it isn’t going
to
work! What you need to do is to find a single wheel, something a simple
as @
bike.wheels.first will do, or do @wheel = Wheel.find(id) and just find
the
one wheel.

To add spokes:

@bike.wheels.first.spokes.build(:spoke_field_1 => “blah”)

To remove a spoke:

@bike.wheels.first.spokes - Spoke.find(spoke_id)

To edit a spoke:

@bike.wheels.first.spokes.find(id).update_attributes(params[:spoke])

I wouldn’t think that would work, because you’re not changing the
associations themselves (i.e. adding/removing records), but you’re
editing
instances of the single records.

I can’t think of another way to do this, sorry. If it’s one value you
could
loop through and do update_attribute(“field”,“value”), and
update_attributes
which I guess you know about already.

Sorry, I should have been more clear, I’m aware of how the collections
work, that was pseudo-code. I’m doing it properly in my real code.

#Pseudo code
b = bike.find(id)
then I loop through b.wheels
loop through wheel.spokes
spoke.thing = “newvalue”
end
end

b.save!

It was a hypothetical example, things in my real DB are all correct
and don’t break any of the normal forms, one pk and one foreign key to
link each record to it’s parent.

According to Ryan’s reply above, Save’s are only propagated (to
descendents) in Ruby model objects when there are insertions or
deletions, not when the fields have been changed.

Thanks,
Danny

On Jan 6, 3:14 pm, Daniel B. [email protected] wrote:

Here’s what I want to do, update a bunch of Spokes that all belong to
one Bike but do it all with one Save! method call.

I recommend (as I have in another thread) that you not do this.

Third normal form states that every column in a table should be
dependent on the primary key. Well, in this case, one of the columns
in the spokes table appears to be dependent not on its primary key,
but on its associated bike’s primary key.

Just my $.02.

///ark

It’s true - they’re done automatically on create, but not on update.

Ryan B. covers this in his screencast on managing multiple models
with 1 form (#75 Complex Forms Part 3 - RailsCasts). It’s relatively
simple to iterate through the child records using something like
def save_wheels
wheels.each do |w|
w.save(false)
end
end

It assumes of course that you have updated their attributes and have a
has_many :wheels in the Bike model.

and calling this method (of the Bike model) with a callback in the
Bike model
after_update :save_wheels

This way, the children are automatically saved when the parent is
saved.

MC

eeew @ .save(false)

Take this as a warning to be very careful when using .save(false),
passing
in false skips all validations and you might not get desired results.

On Jan 8, 2008 9:15 AM, [email protected] [email protected]
wrote:

end

deletions, not when the fields have been changed.

one Bike but do it all with one Save! method call.
///ark


Ryan B.

Feel free to add me to MSN and/or GTalk as this email.