diff options
author | Neeraj Singh <neerajdotname@gmail.com> | 2010-06-30 07:14:09 -0400 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2010-07-08 22:43:18 +0200 |
commit | 01629d180468049d17a8be6900e27a4f0d2b18c4 (patch) | |
tree | d3292821180ce99b8d9f53c35ab7b32b67364c95 | |
parent | 690352dce492938ab54a4b7e2befbd0a6931de3c (diff) | |
download | rails-01629d180468049d17a8be6900e27a4f0d2b18c4.tar.gz rails-01629d180468049d17a8be6900e27a4f0d2b18c4.tar.bz2 rails-01629d180468049d17a8be6900e27a4f0d2b18c4.zip |
This patch changes update_attribute implementatino so:
- it will only save the attribute it has been asked to save and not all dirty attributes
- it does not invoke callbacks
- it does change updated_at/on
Signed-off-by: José Valim <jose.valim@gmail.com>
-rw-r--r-- | activerecord/lib/active_record/persistence.rb | 17 | ||||
-rw-r--r-- | activerecord/lib/active_record/timestamp.rb | 12 | ||||
-rw-r--r-- | activerecord/test/cases/base_test.rb | 40 | ||||
-rw-r--r-- | activerecord/test/cases/dirty_test.rb | 7 | ||||
-rw-r--r-- | activerecord/test/cases/nested_attributes_test.rb | 18 |
5 files changed, 74 insertions, 20 deletions
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 50166c4385..8d093c81de 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -102,12 +102,19 @@ module ActiveRecord became end - # Updates a single attribute and saves the record without going through the normal validation procedure. - # This is especially useful for boolean flags on existing records. The regular +update_attribute+ method - # in Base is replaced with this when the validations module is mixed in, which it is by default. + # Updates a single attribute and saves the record without going through the normal validation procedure + # or callbacks. This is especially useful for boolean flags on existing records. def update_attribute(name, value) send("#{name}=", value) - save(:validate => false) + primary_key = self.class.primary_key + h = {name => value} + if should_record_update_timestamps + self.send(:record_update_timestamps) + current_time = current_time_from_proper_timezone + timestamp_attributes_for_update_in_model.each { |column| h.merge!(column => current_time) } + end + self.class.update_all(h, {primary_key => self[primary_key]}) == 1 + @changed_attributes.delete(name.to_s) end # Updates all the attributes from the passed-in Hash and saves the record. @@ -234,4 +241,4 @@ module ActiveRecord end end end -end
\ No newline at end of file +end diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index da8324ddcc..e6d52744df 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -58,14 +58,22 @@ module ActiveRecord end def update(*args) #:nodoc: - if record_timestamps && (!partial_updates? || changed?) + record_update_timestamps + super + end + + def record_update_timestamps + if should_record_update_timestamps current_time = current_time_from_proper_timezone timestamp_attributes_for_update_in_model.each { |column| write_attribute(column.to_s, current_time) } end + end - super + def should_record_update_timestamps + record_timestamps && (!partial_updates? || changed?) end + def timestamp_attributes_for_update #:nodoc: [:updated_at, :updated_on] end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 329ca38f99..09bdd13cd4 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -893,6 +893,46 @@ class BasicsTest < ActiveRecord::TestCase assert !Topic.find(1).approved? end + def test_update_attribute_with_one_changed_and_one_updated + t = Topic.order('id').limit(1).first + title, author_name = t.title, t.author_name + t.author_name = 'John' + t.update_attribute(:title, 'super_title') + assert_equal 'John', t.author_name + assert_equal 'super_title', t.title + assert t.changed?, "topic should have changed" + assert t.author_name_changed?, "author_name should have changed" + assert !t.title_changed?, "title should not have changed" + assert_nil t.title_change, 'title change should be nil' + assert_equal ['author_name'], t.changed + + t.reload + assert_equal 'David', t.author_name + assert_equal 'super_title', t.title + end + + def test_update_attribute_with_one_updated + t = Topic.first + title = t.title + t.update_attribute(:title, 'super_title') + assert_equal 'super_title', t.title + assert !t.changed?, "topic should not have changed" + assert !t.title_changed?, "title should not have changed" + assert_nil t.title_change, 'title change should be nil' + + t.reload + assert_equal 'super_title', t.title + end + + def test_update_attribute_for_udpated_at_on + developer = Developer.find(1) + updated_at = developer.updated_at + developer.update_attribute(:salary, 80001) + assert_not_equal updated_at, developer.updated_at + developer.reload + assert_not_equal updated_at, developer.updated_at + end + def test_update_attributes topic = Topic.find(1) assert !topic.approved? diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 75f7453aa9..837386ed24 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -475,10 +475,9 @@ class DirtyTest < ActiveRecord::TestCase pirate = Pirate.find_by_catchphrase("Ahoy!") pirate.update_attribute(:catchphrase, "Ninjas suck!") - assert_equal 2, pirate.previous_changes.size - assert_equal ["Ahoy!", "Ninjas suck!"], pirate.previous_changes['catchphrase'] - assert_not_nil pirate.previous_changes['updated_on'][0] - assert_not_nil pirate.previous_changes['updated_on'][1] + assert_equal 0, pirate.previous_changes.size + assert_nil pirate.previous_changes['catchphrase'] + assert_nil pirate.previous_changes['updated_on'] assert !pirate.previous_changes.key?('parrot_id') assert !pirate.previous_changes.key?('created_on') end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 62237f955b..c9ea0d8c40 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -195,7 +195,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase [1, '1', true, 'true'].each do |truth| @pirate.reload.create_ship(:name => 'Mister Pablo') assert_difference('Ship.count', -1) do - @pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => truth }) + @pirate.update_attributes(:ship_attributes => { :id => @pirate.ship.id, :_destroy => truth }) end end end @@ -203,7 +203,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy [nil, '0', 0, 'false', false].each do |not_truth| assert_no_difference('Ship.count') do - @pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => not_truth }) + @pirate.update_attributes(:ship_attributes => { :id => @pirate.ship.id, :_destroy => not_truth }) end end end @@ -212,7 +212,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase Pirate.accepts_nested_attributes_for :ship, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? } assert_no_difference('Ship.count') do - @pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => '1' }) + @pirate.update_attributes(:ship_attributes => { :id => @pirate.ship.id, :_destroy => '1' }) end Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } @@ -247,13 +247,13 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_accept_update_only_option - @pirate.update_attribute(:update_only_ship_attributes, { :id => @pirate.ship.id, :name => 'Mayflower' }) + @pirate.update_attributes(:update_only_ship_attributes => { :id => @pirate.ship.id, :name => 'Mayflower' }) end def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true @ship.delete assert_difference('Ship.count', 1) do - @pirate.reload.update_attribute(:update_only_ship_attributes, { :name => 'Mayflower' }) + @pirate.reload.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower' }) end end @@ -353,7 +353,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase [1, '1', true, 'true'].each do |truth| @ship.reload.create_pirate(:catchphrase => 'Arr') assert_difference('Pirate.count', -1) do - @ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => truth }) + @ship.update_attributes(:pirate_attributes => { :id => @ship.pirate.id, :_destroy => truth }) end end end @@ -361,7 +361,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy [nil, '0', 0, 'false', false].each do |not_truth| assert_no_difference('Pirate.count') do - @ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => not_truth }) + @ship.update_attributes(:pirate_attributes => { :id => @ship.pirate.id, :_destroy => not_truth }) end end end @@ -370,7 +370,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase Ship.accepts_nested_attributes_for :pirate, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? } assert_no_difference('Pirate.count') do - @ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => '1' }) + @ship.update_attributes(:pirate_attributes => { :id => @ship.pirate.id, :_destroy => '1' }) end Ship.accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } @@ -398,7 +398,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true @pirate.delete assert_difference('Pirate.count', 1) do - @ship.reload.update_attribute(:update_only_pirate_attributes, { :catchphrase => 'Arr' }) + @ship.reload.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr' }) end end |