diff options
-rw-r--r-- | activerecord/lib/active_record/attribute_assignment.rb | 4 | ||||
-rw-r--r-- | activerecord/lib/active_record/core.rb | 19 | ||||
-rw-r--r-- | activerecord/test/cases/mass_assignment_security_test.rb | 22 | ||||
-rw-r--r-- | activerecord/test/models/person.rb | 21 |
4 files changed, 55 insertions, 11 deletions
diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb index bf9fe70b31..e0bf80142a 100644 --- a/activerecord/lib/active_record/attribute_assignment.rb +++ b/activerecord/lib/active_record/attribute_assignment.rb @@ -69,6 +69,7 @@ module ActiveRecord attributes = new_attributes.stringify_keys multi_parameter_attributes = [] nested_parameter_attributes = [] + previous_options = @mass_assignment_options @mass_assignment_options = options unless options[:without_protection] @@ -94,8 +95,9 @@ module ActiveRecord send("#{k}=", v) end - @mass_assignment_options = nil assign_multiparameter_attributes(multi_parameter_attributes) + ensure + @mass_assignment_options = previous_options end protected diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 1fa6c701bb..dbad561ca2 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -380,15 +380,16 @@ module ActiveRecord @attributes[pk] = nil unless @attributes.key?(pk) - @aggregation_cache = {} - @association_cache = {} - @attributes_cache = {} - @previously_changed = {} - @changed_attributes = {} - @readonly = false - @destroyed = false - @marked_for_destruction = false - @new_record = true + @aggregation_cache = {} + @association_cache = {} + @attributes_cache = {} + @previously_changed = {} + @changed_attributes = {} + @readonly = false + @destroyed = false + @marked_for_destruction = false + @new_record = true + @mass_assignment_options = nil end end end diff --git a/activerecord/test/cases/mass_assignment_security_test.rb b/activerecord/test/cases/mass_assignment_security_test.rb index 2f98d3c646..1b5421c25e 100644 --- a/activerecord/test/cases/mass_assignment_security_test.rb +++ b/activerecord/test/cases/mass_assignment_security_test.rb @@ -878,4 +878,26 @@ class MassAssignmentSecurityNestedAttributesTest < ActiveRecord::TestCase assert_all_attributes(person.best_friends.first) end + def test_mass_assignment_options_are_reset_after_exception + person = NestedPerson.create!({ :first_name => 'David', :gender => 'm' }, :as => :admin) + person.create_best_friend!({ :first_name => 'Jeremy', :gender => 'm' }, :as => :admin) + + attributes = { :best_friend_attributes => { :comments => 'rides a sweet bike' } } + assert_raises(RuntimeError) { person.assign_attributes(attributes, :as => :admin) } + assert_equal 'm', person.best_friend.gender + + person.best_friend_attributes = { :gender => 'f' } + assert_equal 'm', person.best_friend.gender + end + + def test_mass_assignment_options_are_nested_correctly + person = NestedPerson.create!({ :first_name => 'David', :gender => 'm' }, :as => :admin) + person.create_best_friend!({ :first_name => 'Jeremy', :gender => 'm' }, :as => :admin) + + attributes = { :best_friend_first_name => 'Josh', :best_friend_attributes => { :gender => 'f' } } + person.assign_attributes(attributes, :as => :admin) + assert_equal 'Josh', person.best_friend.first_name + assert_equal 'f', person.best_friend.gender + end + end diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb index d5c0b351aa..33cd6020a1 100644 --- a/activerecord/test/models/person.rb +++ b/activerecord/test/models/person.rb @@ -88,6 +88,25 @@ class TightDescendant < TightPerson; end class RichPerson < ActiveRecord::Base self.table_name = 'people' - + has_and_belongs_to_many :treasures, :join_table => 'peoples_treasures' end + +class NestedPerson < ActiveRecord::Base + self.table_name = 'people' + + attr_accessible :first_name, :best_friend_first_name, :best_friend_attributes + attr_accessible :first_name, :gender, :comments, :as => :admin + attr_accessible :best_friend_attributes, :best_friend_first_name, :as => :admin + + has_one :best_friend, :class_name => 'NestedPerson', :foreign_key => :best_friend_id + accepts_nested_attributes_for :best_friend, :update_only => true + + def comments=(new_comments) + raise RuntimeError + end + + def best_friend_first_name=(new_name) + assign_attributes({ :best_friend_attributes => { :first_name => new_name } }) + end +end
\ No newline at end of file |