aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Pfeifer <aaron.pfeifer@gmail.com>2013-02-26 09:35:03 -0500
committerAaron Pfeifer <aaron.pfeifer@gmail.com>2013-03-18 22:09:01 -0400
commita240e526a8b4c5948a1c2a8ec49b6e2d1ad6ad23 (patch)
treef6639671decafa03597722f77238607b1f31bfbc
parent111611b511c27ec29be6a8837de6d8f25cded5a7 (diff)
downloadrails-a240e526a8b4c5948a1c2a8ec49b6e2d1ad6ad23.tar.gz
rails-a240e526a8b4c5948a1c2a8ec49b6e2d1ad6ad23.tar.bz2
rails-a240e526a8b4c5948a1c2a8ec49b6e2d1ad6ad23.zip
Fix ActiveRecord locking column defaults not getting persisted
When partial inserts are enabled, overridden db defaults are ignored. This results in locking columns having a nil value for new records if the db default is null. This happens because the list of changed attributes for new records is always assumed to be empty. Solution: When a new record's default attributes are set, also initialize the list of changed attributes by comparing current values against what's stored as the column defaults in the database.
-rw-r--r--activerecord/lib/active_record/core.rb14
-rw-r--r--activerecord/test/cases/locking_test.rb8
2 files changed, 19 insertions, 3 deletions
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index aa56219755..1908448f90 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -176,6 +176,7 @@ module ActiveRecord
@columns_hash = self.class.column_types.dup
init_internals
+ init_changed_attributes
ensure_proper_type
populate_with_current_scope_attributes
@@ -246,9 +247,7 @@ module ActiveRecord
run_callbacks(:initialize) unless _initialize_callbacks.empty?
@changed_attributes = {}
- self.class.column_defaults.each do |attr, orig_value|
- @changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
- end
+ init_changed_attributes
@aggregation_cache = {}
@association_cache = {}
@@ -433,5 +432,14 @@ module ActiveRecord
@transaction_state = nil
@reflects_state = [false]
end
+
+ def init_changed_attributes
+ # Intentionally avoid using #column_defaults since overriden defaults (as is done in
+ # optimistic locking) won't get written unless they get marked as changed
+ self.class.columns.each do |c|
+ attr, orig_value = c.name, c.default
+ @changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
+ end
+ end
end
end
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 0c896beb1d..77891b9156 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -193,11 +193,19 @@ class OptimisticLockingTest < ActiveRecord::TestCase
def test_lock_without_default_sets_version_to_zero
t1 = LockWithoutDefault.new
assert_equal 0, t1.lock_version
+
+ t1.save
+ t1 = LockWithoutDefault.find(t1.id)
+ assert_equal 0, t1.lock_version
end
def test_lock_with_custom_column_without_default_sets_version_to_zero
t1 = LockWithCustomColumnWithoutDefault.new
assert_equal 0, t1.custom_lock_version
+
+ t1.save
+ t1 = LockWithCustomColumnWithoutDefault.find(t1.id)
+ assert_equal 0, t1.custom_lock_version
end
def test_readonly_attributes