> > Hi!
> > I'm struggling with this for a while and i'm new to rails so it's
> > quite frustrating 
> > I need to create new model object based on old one with only few
> > changes.
> > I have desings -> has many -> lines -> has_many -> fields
> > I've got input from user in array like this:
> > field =>[
> > line_id =>[ fiel_id => field_value]
> > ]
> > so I iterate:
> > input[:field].each do |line_id, line|
> > line.each do |field_id, field_value|
> > design.lines.find(line_id).fields.find(field_id).value =
> > field_value
> > design.lines.find(line_id).fields.find(field_id).something =
> > field_value
> > end
> > end
> You're finding stuff and assigning new values to what was found but
> not saving these changes back to the db as far as I can tell here.
> Retrieve the field once
> field=design.lines.find(line_id).fields.find(field_id)
> update its values and then save it
> field.something = ...
> field.save (or field.save!)
> You're not creating anything new, just updating old.
> If you want a new field, you'll need to create it:
> design.lines.find(line_id).fields.push(Field.new({hash-of-
> attributes}))
> This will add a new field to design's line with line_id.
> You could probably do something like
> new_field=Field.new(field.attributes)
> to create a new field with the same attributes as the existing
> 'field', alter
> its values as required and then push it onto the fields collection:
> design.lines.find(line_id).fields.push(Field.new(new_field))
> Be careful with names like 'field' - I don't know if they'll clash
> with rails names.
> Maybe also consider not chaining all those 'finds' together in one
> line.
> Find each thing and store it in a local variable or an instance
> variable so
> you won't have to get it again during the action.
> --
> Daniel Bush
I followed your suggestion and write this code:
1 new_design = Design.new design.attributes
There's actually a 'clone' method which is probably better than what I
suggested before.
new_design = design.clone
But don't forget that you'll need to save it at some point.
2 design.background.colour_id = 123
3 new_design.background = Background.new
design.background.attributes
4 lines = design.lines
5 for line in lines
6 new_line = Line.new line.attributes
7 fields = line.fields
8 for field in fields
9 field.value = input_data[:field][line.id][field.id]
10 new_field = Field.new field.attributes
11 new_line.fields.push(new_field)
12 end
13 new_design.lines.push(new_line)
14 end
and now I'v got error that i have nil object in line 5, 8, 9 so it'
seems that rails think's design has no lines.
I'm guessing it's line 9 and it has something to do with input_data
[:field] or input_data[:field][line.id] that's returning nil. 5 and 8
are just part of the looping which means there are lines and each line
does have fields.
You could compress your code a little eg
design.lines.each do |line|
new_line = line.clone
...
line.fields.each do |field|
...
end
end
I didn't mean to break everything up into separate assignments;
whatever you think is best.