From a240e526a8b4c5948a1c2a8ec49b6e2d1ad6ad23 Mon Sep 17 00:00:00 2001
From: Aaron Pfeifer <aaron.pfeifer@gmail.com>
Date: Tue, 26 Feb 2013 09:35:03 -0500
Subject: 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.
---
 activerecord/lib/active_record/core.rb | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

(limited to 'activerecord/lib')

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
-- 
cgit v1.2.3