From 4db10bce7b5ca794c4d408de3b8002bf58233bb7 Mon Sep 17 00:00:00 2001 From: pleax Date: Mon, 17 May 2010 01:47:56 +0400 Subject: AR::Base#clone fixed to set dirty bits for cloned object [#2919 state:committed] Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/base.rb | 8 +++++- activerecord/test/cases/base_test.rb | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 37675d8ab1..18f75af11b 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1463,12 +1463,18 @@ module ActiveRecord #:nodoc: callback(:after_initialize) if respond_to_without_attributes?(:after_initialize) cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) cloned_attributes.delete(self.class.primary_key) + @attributes = cloned_attributes + + @changed_attributes = {} + attributes_from_column_definition.each do |attr, orig_value| + @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr]) + end + clear_aggregation_cache @attributes_cache = {} @new_record = true ensure_proper_type - @changed_attributes = other.changed_attributes.dup if scope = self.class.send(:current_scoped_methods) create_with = scope.scope_for_create diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index b7ae619787..7c4d92f3f8 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1456,6 +1456,56 @@ class BasicsTest < ActiveRecord::TestCase assert_kind_of Client, clone end + def test_clone_of_new_object_with_defaults + developer = Developer.new + assert !developer.name_changed? + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert !cloned_developer.name_changed? + assert !cloned_developer.salary_changed? + end + + def test_clone_of_new_object_marks_attributes_as_dirty + developer = Developer.new :name => 'Bjorn', :salary => 100000 + assert developer.name_changed? + assert developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? + assert cloned_developer.salary_changed? + end + + def test_clone_of_new_object_marks_as_dirty_only_changed_attributes + developer = Developer.new :name => 'Bjorn' + assert developer.name_changed? # obviously + assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed + + cloned_developer = developer.clone + assert cloned_developer.name_changed? + assert !cloned_developer.salary_changed? # ... and cloned instance should behave same + end + + def test_clone_of_saved_object_marks_attributes_as_dirty + developer = Developer.create! :name => 'Bjorn', :salary => 100000 + assert !developer.name_changed? + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? # both attributes differ from defaults + assert cloned_developer.salary_changed? + end + + def test_clone_of_saved_object_marks_as_dirty_only_changed_attributes + developer = Developer.create! :name => 'Bjorn' + assert !developer.name_changed? # both attributes of saved object should be threated as not changed + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? # ... but on cloned object should be + assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be threated as not changed on cloned instance + end + def test_bignum company = Company.find(1) company.rating = 2147483647 -- cgit v1.2.3