Skip to content
This repository
Browse code

New #update_columns method.

  • Loading branch information...
commit 87ffc3662fc023d33e3baaf2fadb09ce4bece5b5 1 parent 2d6af1d
Sebastian Martinez authored May 21, 2011 rafaelfranca committed July 24, 2012
17  activerecord/lib/active_record/persistence.rb
@@ -211,6 +211,23 @@ def update_attributes!(attributes, options = {})
211 211
       end
212 212
     end
213 213
 
  214
+    # Updates the attributes from the passed-in hash, without calling save.
  215
+    #
  216
+    # * Validation is skipped.
  217
+    # * Callbacks are skipped.
  218
+    # * updated_at/updated_on column is not updated if that column is available.
  219
+    #
  220
+    # Raises an +ActiveRecordError+ when called on new objects, or when at least
  221
+    # one of the attributes is marked as readonly.
  222
+    def update_columns(attributes)
  223
+      raise ActiveRecordError, "can not update on a new record object" unless persisted?
  224
+      attributes.each_key {|key| raise ActiveRecordError, "#{key.to_s} is marked as readonly" if self.class.readonly_attributes.include?(key.to_s) }
  225
+      attributes.each do |k,v|
  226
+        raw_write_attribute(k,v)
  227
+      end
  228
+      self.class.where(self.class.primary_key => id).update_all(attributes) == 1
  229
+    end
  230
+
214 231
     # Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
215 232
     # The increment is performed directly on the underlying attribute, no setter is invoked.
216 233
     # Only makes sense for number-based attributes. Returns +self+.
57  activerecord/test/cases/persistence_test.rb
@@ -461,6 +461,63 @@ def test_update_column_with_one_changed_and_one_updated
461 461
     assert_equal 'super_title', t.title
462 462
   end
463 463
 
  464
+  def test_update_columns
  465
+    topic = Topic.find(1)
  466
+    topic.update_columns({ "approved" => true, title: "Sebastian Topic" })
  467
+    assert topic.approved?
  468
+    assert_equal "Sebastian Topic", topic.title
  469
+    topic.reload
  470
+    assert topic.approved?
  471
+    assert_equal "Sebastian Topic", topic.title
  472
+  end
  473
+
  474
+  def test_update_columns_should_raise_exception_if_new_record
  475
+    topic = Topic.new
  476
+    assert_raises(ActiveRecord::ActiveRecordError) { topic.update_columns({ approved: false }) }
  477
+  end
  478
+
  479
+  def test_update_columns_should_not_leave_the_object_dirty
  480
+    topic = Topic.find(1)
  481
+    topic.update_attributes({ "content" => "Have a nice day", :author_name => "Jose" })
  482
+
  483
+    topic.reload
  484
+    topic.update_columns({ content: "You too", "author_name" => "Sebastian" })
  485
+    assert_equal [], topic.changed
  486
+
  487
+    topic.reload
  488
+    topic.update_columns({ content: "Have a nice day", author_name: "Jose" })
  489
+    assert_equal [], topic.changed
  490
+  end
  491
+
  492
+  def test_update_columns_with_one_readonly_attribute
  493
+    minivan = Minivan.find('m1')
  494
+    prev_color = minivan.color
  495
+    prev_name = minivan.name
  496
+    assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_columns({ name: "My old minivan", color: 'black' }) }
  497
+    assert_equal prev_color, minivan.color
  498
+    assert_equal prev_name, minivan.name
  499
+
  500
+    minivan.reload
  501
+    assert_equal prev_color, minivan.color
  502
+    assert_equal prev_name, minivan.name
  503
+  end
  504
+
  505
+  def test_update_columns_should_not_modify_updated_at
  506
+    developer = Developer.find(1)
  507
+    prev_month = Time.now.prev_month
  508
+
  509
+    developer.update_column(:updated_at, prev_month)
  510
+    assert_equal prev_month, developer.updated_at
  511
+
  512
+    developer.update_columns({ salary: 80000 })
  513
+    assert_equal prev_month, developer.updated_at
  514
+    assert_equal 80000, developer.salary
  515
+
  516
+    developer.reload
  517
+    assert_equal prev_month.to_i, developer.updated_at.to_i
  518
+    assert_equal 80000, developer.salary
  519
+  end
  520
+
464 521
   def test_update_attributes
465 522
     topic = Topic.find(1)
466 523
     assert !topic.approved?
2  guides/source/active_record_validations_callbacks.textile
Source Rendered
@@ -86,6 +86,7 @@ The following methods skip validations, and will save the object to the database
86 86
 * +update_all+
87 87
 * +update_attribute+
88 88
 * +update_column+
  89
+* +update_columns+
89 90
 * +update_counters+
90 91
 
91 92
 Note that +save+ also has the ability to skip validations if passed +:validate => false+ as argument. This technique should be used with caution.
@@ -1082,6 +1083,7 @@ Just as with validations, it is also possible to skip callbacks. These methods s
1082 1083
 * +toggle+
1083 1084
 * +touch+
1084 1085
 * +update_column+
  1086
+* +update_columns+
1085 1087
 * +update_all+
1086 1088
 * +update_counters+
1087 1089
 

0 notes on commit 87ffc36

Please sign in to comment.
Something went wrong with that request. Please try again.