Skip to content

Commit fc07905

Browse files
authored
Merge pull request rails#52792 from jimnanney/order-dependent-nested-attributes
Change assign_attributes to assign the association's _id first. Fixes…
2 parents 987d3fb + 9259af6 commit fc07905

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

activerecord/lib/active_record/attribute_assignment.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,29 @@ module ActiveRecord
44
module AttributeAssignment
55
private
66
def _assign_attributes(attributes)
7-
multi_parameter_attributes = nil
7+
multi_parameter_attributes = nested_parameter_attributes = nil
88

99
attributes.each do |k, v|
1010
key = k.to_s
1111

1212
if key.include?("(")
1313
(multi_parameter_attributes ||= {})[key] = v
14+
elsif v.is_a?(Hash)
15+
(nested_parameter_attributes ||= {})[key] = v
1416
else
1517
_assign_attribute(key, v)
1618
end
1719
end
1820

21+
assign_nested_parameter_attributes(nested_parameter_attributes) if nested_parameter_attributes
1922
assign_multiparameter_attributes(multi_parameter_attributes) if multi_parameter_attributes
2023
end
2124

25+
# Assign any deferred nested attributes after the base attributes have been set.
26+
def assign_nested_parameter_attributes(pairs)
27+
pairs.each { |k, v| _assign_attribute(k, v) }
28+
end
29+
2230
# Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
2331
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
2432
# So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate

activerecord/test/cases/nested_attributes_test.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,15 @@ def test_should_work_with_update_as_well
372372
assert_equal "Mister Pablo", @pirate.ship.name
373373
end
374374

375+
def test_should_defer_updating_nested_associations_until_after_base_attributes_are_set
376+
ship = @pirate.ship
377+
378+
ship_part = ShipPart.new
379+
ship_part.attributes = { ship_attributes: { name: "Prometheus" }, ship_id: ship.id }
380+
381+
assert_equal "Prometheus", ship_part.ship.name
382+
end
383+
375384
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
376385
@pirate.attributes = { ship_attributes: { id: @ship.id, _destroy: "1" } }
377386

0 commit comments

Comments
 (0)