Permalink
Browse files

Remove update_attribute.

Historically, update_attribute and update_attributes are similar, but
with one big difference: update_attribute does not run validations.
These two methods are really easy to confuse given their similar
names. Therefore, update_attribute is being removed in favor of
update_column.

See the thread on rails-core here:
https://groups.google.com/forum/?fromgroups#!topic/rubyonrails-core/BWPUTK7WvYA
  • Loading branch information...
steveklabnik committed Jun 14, 2012
1 parent 99c9d18 commit a7f4b0a1231bf3c65db2ad4066da78c3da5ffb01
@@ -36,7 +36,7 @@ def delete(method = options[:dependent])
when :destroy
target.destroy
when :nullify
target.update_attribute(reflection.foreign_key, nil)
target.update_column(reflection.foreign_key, nil)
end
end
end
@@ -238,7 +238,7 @@ def initialize
# add_column :people, :salary, :integer
# Person.reset_column_information
# Person.all.each do |p|
# p.update_attribute :salary, SalaryCalculator.compute(p)
# p.update_column :salary, SalaryCalculator.compute(p)
# end
# end
# end
@@ -258,7 +258,7 @@ def initialize
# ...
# say_with_time "Updating salaries..." do
# Person.all.each do |p|
# p.update_attribute :salary, SalaryCalculator.compute(p)
# p.update_column :salary, SalaryCalculator.compute(p)
# end
# end
# ...
@@ -167,21 +167,6 @@ def becomes(klass)
became
end
# Updates a single attribute and saves the record.
# This is especially useful for boolean flags on existing records. Also note that
#
# * Validation is skipped.
# * Callbacks are invoked.
# * updated_at/updated_on column is updated if that column is available.
# * Updates all the attributes that are dirty in this object.
#
def update_attribute(name, value)
name = name.to_s
verify_readonly_attribute(name)
send("#{name}=", value)
save(:validate => false)
end
# Updates a single attribute of an object, without calling save.
#
# * Validation is skipped.
@@ -240,7 +225,7 @@ def increment(attribute, by = 1)
# Saving is not subjected to validation checks. Returns +true+ if the
# record could be saved.
def increment!(attribute, by = 1)
increment(attribute, by).update_attribute(attribute, self[attribute])
increment(attribute, by).update_column(attribute, self[attribute])
end
# Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
@@ -257,7 +242,7 @@ def decrement(attribute, by = 1)
# Saving is not subjected to validation checks. Returns +true+ if the
# record could be saved.
def decrement!(attribute, by = 1)
decrement(attribute, by).update_attribute(attribute, self[attribute])
decrement(attribute, by).update_column(attribute, self[attribute])
end
# Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
@@ -274,7 +259,7 @@ def toggle(attribute)
# Saving is not subjected to validation checks. Returns +true+ if the
# record could be saved.
def toggle!(attribute)
toggle(attribute).update_attribute(attribute, self[attribute])
toggle(attribute).update_column(attribute, self[attribute])
end
# Reloads the attributes of this object from the database.
@@ -1935,7 +1935,7 @@ def test_cache_key_format_for_existing_record_with_updated_at
def test_cache_key_format_for_existing_record_with_nil_updated_at
dev = Developer.first
dev.update_attribute(:updated_at, nil)
dev.update_column(:updated_at, nil)
assert_match(/\/#{dev.id}$/, dev.cache_key)
end
@@ -498,7 +498,7 @@ def test_previous_changes
assert !pirate.previous_changes.key?('created_on')
pirate = Pirate.find_by_catchphrase("Ahoy!")
pirate.update_attribute(:catchphrase, "Ninjas suck!")
pirate.update_column(:catchphrase, "Ninjas suck!")
assert_equal 2, pirate.previous_changes.size
assert_equal ["Ahoy!", "Ninjas suck!"], pirate.previous_changes['catchphrase']
@@ -371,71 +371,10 @@ def test_destroy_record_with_associations
assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
end
def test_update_attribute
assert !Topic.find(1).approved?
Topic.find(1).update_attribute("approved", true)
assert Topic.find(1).approved?
Topic.find(1).update_attribute(:approved, false)
assert !Topic.find(1).approved?
end
def test_update_attribute_does_not_choke_on_nil
assert Topic.find(1).update_attributes(nil)
end
def test_update_attribute_for_readonly_attribute
minivan = Minivan.find('m1')
assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
end
# This test is correct, but it is hard to fix it since
# update_attribute trigger simply call save! that triggers
# all callbacks.
# 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
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_updated_at_on
developer = Developer.find(1)
prev_month = Time.now.prev_month
developer.update_attribute(:updated_at, prev_month)
assert_equal prev_month, developer.updated_at
developer.update_attribute(:salary, 80001)
assert_not_equal prev_month, developer.updated_at
developer.reload
assert_not_equal prev_month, developer.updated_at
end
def test_update_column
topic = Topic.find(1)
topic.update_column("approved", true)
@@ -467,7 +406,7 @@ def test_update_column_should_raise_exception_if_new_record
def test_update_column_should_not_leave_the_object_dirty
topic = Topic.find(1)
topic.update_attribute("content", "Have a nice day")
topic.update_column("content", "Have a nice day")
topic.reload
topic.update_column(:content, "You too")
@@ -11,7 +11,7 @@ class TimestampTest < ActiveRecord::TestCase
def setup
@developer = Developer.first
@developer.update_attribute(:updated_at, Time.now.prev_month)
@developer.update_column(:updated_at, Time.now.prev_month)
@previously_updated_at = @developer.updated_at
end
@@ -133,7 +133,7 @@ def test_touching_a_record_with_a_belongs_to_that_uses_a_counter_cache_should_up
pet = Pet.first
owner = pet.owner
owner.update_attribute(:happy_at, 3.days.ago)
owner.update_column(:happy_at, 3.days.ago)
previously_owner_updated_at = owner.updated_at
pet.name = "I'm a parrot"

4 comments on commit a7f4b0a

@adsummos

This comment has been minimized.

Show comment
Hide comment
@adsummos

adsummos Jun 20, 2012

can't we at least deprecate update_attribute before removing it?

adsummos replied Jun 20, 2012

can't we at least deprecate update_attribute before removing it?

@steveklabnik

This comment has been minimized.

Show comment
Hide comment
@steveklabnik

steveklabnik Jun 20, 2012

Member

@adsummos it is deprecated in 3.2.x.

Member

steveklabnik replied Jun 20, 2012

@adsummos it is deprecated in 3.2.x.

@korny

This comment has been minimized.

Show comment
Hide comment
@korny

korny Oct 7, 2012

Contributor

Smart move.

Contributor

korny replied Oct 7, 2012

Smart move.

@Vinay50

This comment has been minimized.

Show comment
Hide comment
@Vinay50

Vinay50 replied Feb 17, 2013

wow.

Please sign in to comment.