diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index e3122d1..1b7f0c6 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -227,11 +227,18 @@ module ActiveRecord
marked_for_destruction?
end
+ # See ActionView::Helpers::FormHelper::fields_for for more info.
+ def _unlink
+ # TODO: should return true when validation of a form fails and
+ # a record has been marked for unlinking.
+ false
+ end
+
private
# Attribute hash keys that should not be assigned as normal attributes.
# These hash keys are nested attributes implementation details.
- UNASSIGNABLE_KEYS = %w{ id _delete }
+ UNASSIGNABLE_KEYS = %w{ id _delete _unlink }
# Assigns the given attributes to the association.
#
@@ -297,8 +304,19 @@ module ActiveRecord
unless reject_new_record?(association_name, attributes)
send(association_name).build(attributes.except(*UNASSIGNABLE_KEYS))
end
- elsif existing_record = send(association_name).detect { |record| record.id.to_s == attributes['id'].to_s }
- assign_to_or_mark_for_destruction(existing_record, attributes, allow_destroy)
+ else
+ existing_record = send(association_name).detect { |record| record.id.to_s == attributes['id'].to_s }
+ if attributes.has_key?("_unlink")
+ # here :autosave doesn't work as I would have expected
+ if has_unlink_flag?(attributes)
+ send(association_name).delete(existing_record)
+ elsif existing_record.nil?
+ existing_record = self.class.reflections[association_name].klass.find(attributes['id'].to_s.to_i)
+ send(association_name).push(existing_record) if existing_record
+ end
+ elsif existing_record
+ assign_to_or_mark_for_destruction(existing_record, attributes, allow_destroy)
+ end
end
end
end
@@ -318,11 +336,17 @@ module ActiveRecord
ConnectionAdapters::Column.value_to_boolean hash['_delete']
end
+ # Determines if a hash contains a truthy _unlink key.
+ def has_unlink_flag?(hash)
+ ConnectionAdapters::Column.value_to_boolean hash['_unlink']
+ end
+
# Determines if a new record should be build by checking for
- # has_delete_flag? or if a :reject_if proc exists for this
- # association and evaluates to +true+.
+ # has_delete_flag? or has_unlink_flag? or if a :reject_if proc
+ # exists for this association and evaluates to +true+.
def reject_new_record?(association_name, attributes)
has_delete_flag?(attributes) ||
+ has_unlink_flag?(attributes) ||
self.class.reject_new_nested_attributes_procs[association_name].try(:call, attributes)
end
end