Skip to content
This repository
Browse code

Revert "Remove update_attribute."

This reverts commit a7f4b0a.

Conflicts:
	activerecord/lib/active_record/associations/has_one_association.rb
	activerecord/lib/active_record/persistence.rb
	activerecord/test/cases/base_test.rb
	activerecord/test/cases/dirty_test.rb
	activerecord/test/cases/timestamp_test.rb
  • Loading branch information...
commit 50bdb924ba26999a468ec4844917cefec39ba08c 1 parent a1d18ed
Rafael Mendonça França authored August 25, 2012
4  activerecord/lib/active_record/migration.rb
@@ -236,7 +236,7 @@ def initialize
236 236
   #       add_column :people, :salary, :integer
237 237
   #       Person.reset_column_information
238 238
   #       Person.all.each do |p|
239  
-  #         p.update_column :salary, SalaryCalculator.compute(p)
  239
+  #         p.update_attribute :salary, SalaryCalculator.compute(p)
240 240
   #       end
241 241
   #     end
242 242
   #   end
@@ -256,7 +256,7 @@ def initialize
256 256
   #     ...
257 257
   #     say_with_time "Updating salaries..." do
258 258
   #       Person.all.each do |p|
259  
-  #         p.update_column :salary, SalaryCalculator.compute(p)
  259
+  #         p.update_attribute :salary, SalaryCalculator.compute(p)
260 260
   #       end
261 261
   #     end
262 262
   #     ...
22  activerecord/lib/active_record/persistence.rb
... ...
@@ -1,4 +1,3 @@
1  
-
2 1
 module ActiveRecord
3 2
   # = Active Record Persistence
4 3
   module Persistence
@@ -166,6 +165,21 @@ def becomes(klass)
166 165
       became
167 166
     end
168 167
 
  168
+    # Updates a single attribute and saves the record.
  169
+    # This is especially useful for boolean flags on existing records. Also note that
  170
+    #
  171
+    # * Validation is skipped.
  172
+    # * Callbacks are invoked.
  173
+    # * updated_at/updated_on column is updated if that column is available.
  174
+    # * Updates all the attributes that are dirty in this object.
  175
+    #
  176
+    def update_attribute(name, value)
  177
+      name = name.to_s
  178
+      verify_readonly_attribute(name)
  179
+      send("#{name}=", value)
  180
+      save(:validate => false)
  181
+    end
  182
+
169 183
     # Updates the attributes of the model from the passed-in hash and saves the
170 184
     # record, all wrapped in a transaction. If the object is invalid, the saving
171 185
     # will fail and false will be returned.
@@ -242,7 +256,7 @@ def increment(attribute, by = 1)
242 256
     # Saving is not subjected to validation checks. Returns +true+ if the
243 257
     # record could be saved.
244 258
     def increment!(attribute, by = 1)
245  
-      increment(attribute, by).update_columns(attribute => self[attribute])
  259
+      increment(attribute, by).update_attribute(attribute, self[attribute])
246 260
     end
247 261
 
248 262
     # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
@@ -259,7 +273,7 @@ def decrement(attribute, by = 1)
259 273
     # Saving is not subjected to validation checks. Returns +true+ if the
260 274
     # record could be saved.
261 275
     def decrement!(attribute, by = 1)
262  
-      decrement(attribute, by).update_columns(attribute => self[attribute])
  276
+      decrement(attribute, by).update_attribute(attribute, self[attribute])
263 277
     end
264 278
 
265 279
     # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
@@ -276,7 +290,7 @@ def toggle(attribute)
276 290
     # Saving is not subjected to validation checks. Returns +true+ if the
277 291
     # record could be saved.
278 292
     def toggle!(attribute)
279  
-      toggle(attribute).update_columns(attribute => self[attribute])
  293
+      toggle(attribute).update_attribute(attribute, self[attribute])
280 294
     end
281 295
 
282 296
     # Reloads the attributes of this object from the database.
12  activerecord/test/cases/dirty_test.rb
@@ -509,6 +509,16 @@ def test_previous_changes
509 509
     assert_not_nil pirate.previous_changes['updated_on'][1]
510 510
     assert !pirate.previous_changes.key?('parrot_id')
511 511
     assert !pirate.previous_changes.key?('created_on')
  512
+
  513
+    pirate = Pirate.find_by_catchphrase("Ahoy!")
  514
+    pirate.update_attribute(:catchphrase, "Ninjas suck!")
  515
+
  516
+    assert_equal 2, pirate.previous_changes.size
  517
+    assert_equal ["Ahoy!", "Ninjas suck!"], pirate.previous_changes['catchphrase']
  518
+    assert_not_nil pirate.previous_changes['updated_on'][0]
  519
+    assert_not_nil pirate.previous_changes['updated_on'][1]
  520
+    assert !pirate.previous_changes.key?('parrot_id')
  521
+    assert !pirate.previous_changes.key?('created_on')
512 522
   end
513 523
 
514 524
   if ActiveRecord::Base.connection.supports_migrations?
@@ -534,7 +544,7 @@ def test_setting_time_attributes_with_time_zone_field_to_same_time_should_not_be
534 544
 
535 545
       pirate = target.create(:created_on => created_on)
536 546
       pirate.reload # Here mysql truncate the usec value to 0
537  
-      
  547
+
538 548
       pirate.created_on = created_on
539 549
       assert !pirate.created_on_changed?
540 550
     end
40  activerecord/test/cases/persistence_test.rb
@@ -371,10 +371,50 @@ def test_destroy_record_with_associations
371 371
     assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
372 372
   end
373 373
 
  374
+  def test_update_attribute
  375
+    assert !Topic.find(1).approved?
  376
+    Topic.find(1).update_attribute("approved", true)
  377
+    assert Topic.find(1).approved?
  378
+
  379
+    Topic.find(1).update_attribute(:approved, false)
  380
+    assert !Topic.find(1).approved?
  381
+  end
  382
+
374 383
   def test_update_attribute_does_not_choke_on_nil
375 384
     assert Topic.find(1).update_attributes(nil)
376 385
   end
377 386
 
  387
+  def test_update_attribute_for_readonly_attribute
  388
+    minivan = Minivan.find('m1')
  389
+    assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
  390
+  end
  391
+
  392
+  def test_update_attribute_with_one_updated
  393
+    t = Topic.first
  394
+    t.update_attribute(:title, 'super_title')
  395
+    assert_equal 'super_title', t.title
  396
+    assert !t.changed?, "topic should not have changed"
  397
+    assert !t.title_changed?, "title should not have changed"
  398
+    assert_nil t.title_change, 'title change should be nil'
  399
+
  400
+    t.reload
  401
+    assert_equal 'super_title', t.title
  402
+  end
  403
+
  404
+  def test_update_attribute_for_updated_at_on
  405
+    developer = Developer.find(1)
  406
+    prev_month = Time.now.prev_month
  407
+
  408
+    developer.update_attribute(:updated_at, prev_month)
  409
+    assert_equal prev_month, developer.updated_at
  410
+
  411
+    developer.update_attribute(:salary, 80001)
  412
+    assert_not_equal prev_month, developer.updated_at
  413
+
  414
+    developer.reload
  415
+    assert_not_equal prev_month, developer.updated_at
  416
+  end
  417
+
378 418
   def test_update_column
379 419
     topic = Topic.find(1)
380 420
     topic.update_column("approved", true)

0 notes on commit 50bdb92

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