Skip to content

Commit

Permalink
Merge pull request #3991 from akaspick/attrfix
Browse files Browse the repository at this point in the history
Allow nested attributes in associations to update values in it's owner o...
  • Loading branch information
jonleighton committed Dec 15, 2011
2 parents ad87752 + 774ff18 commit 0ddb9d6
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 2 deletions.
2 changes: 2 additions & 0 deletions activerecord/lib/active_record/associations/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ def association_class
end

def build_record(attributes, options)
attributes = (attributes || {}).reverse_merge(creation_attributes)

reflection.build_association(attributes, options) do |record|
record.assign_attributes(
create_scope.except(*record.changed),
Expand Down
12 changes: 11 additions & 1 deletion activerecord/lib/active_record/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1776,6 +1776,7 @@ def assign_attributes(new_attributes, options = {})

attributes = new_attributes.stringify_keys
multi_parameter_attributes = []
nested_parameter_attributes = []
@mass_assignment_options = options

unless options[:without_protection]
Expand All @@ -1786,12 +1787,21 @@ def assign_attributes(new_attributes, options = {})
if k.include?("(")
multi_parameter_attributes << [ k, v ]
elsif respond_to?("#{k}=")
send("#{k}=", v)
if v.is_a?(Hash)
nested_parameter_attributes << [ k, v ]
else
send("#{k}=", v)
end
else
raise(UnknownAttributeError, "unknown attribute: #{k}")
end
end

# assign any deferred nested attributes after the base attributes have been set
nested_parameter_attributes.each do |k,v|
send("#{k}=", v)
end

@mass_assignment_options = nil
assign_multiparameter_attributes(multi_parameter_attributes)
end
Expand Down
5 changes: 5 additions & 0 deletions activerecord/test/cases/nested_attributes_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,11 @@ def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name]
end

def test_should_take_a_hash_with_owner_attributes_and_assign_the_attributes_to_the_associated_model
@pirate.birds.create :name => 'bird', :pirate_attributes => {:id => @pirate.id.to_s, :catchphrase => 'Holla!'}
assert_equal 'Holla!', @pirate.reload.catchphrase
end

def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find #{@child_1.class.name} with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
@pirate.attributes = { association_getter => [{ :id => 1234567890 }] }
Expand Down
5 changes: 4 additions & 1 deletion activerecord/test/models/bird.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
class Bird < ActiveRecord::Base
belongs_to :pirate
validates_presence_of :name

accepts_nested_attributes_for :pirate

attr_accessor :cancel_save_from_callback
before_save :cancel_save_callback_method, :if => :cancel_save_from_callback
def cancel_save_callback_method
false
end
end
end

0 comments on commit 0ddb9d6

Please sign in to comment.