Skip to content

Commit

Permalink
Fix ActiveRecord locking column defaults not getting persisted
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
obrie committed Mar 19, 2013
1 parent 111611b commit a240e52
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 3 deletions.
14 changes: 11 additions & 3 deletions activerecord/lib/active_record/core.rb
Expand Up @@ -176,6 +176,7 @@ def initialize(attributes = nil)
@columns_hash = self.class.column_types.dup

init_internals
init_changed_attributes
ensure_proper_type
populate_with_current_scope_attributes

Expand Down Expand Up @@ -246,9 +247,7 @@ def initialize_dup(other) # :nodoc:
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 = {}
Expand Down Expand Up @@ -433,5 +432,14 @@ def init_internals
@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
8 changes: 8 additions & 0 deletions activerecord/test/cases/locking_test.rb
Expand Up @@ -193,11 +193,19 @@ def test_lock_column_is_mass_assignable
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
Expand Down

0 comments on commit a240e52

Please sign in to comment.