aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations/collection_association.rb
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2011-05-14 18:45:11 +0100
committerJon Leighton <j@jonathanleighton.com>2011-05-14 19:49:22 +0100
commit6660beef367a888ac633cc03d1d7157737e6b2cb (patch)
tree522db40671f58718463624271193a3e3369b4c0b /activerecord/lib/active_record/associations/collection_association.rb
parente7e1d83ddfceeddd890ecd251bf81e18d3b553cb (diff)
downloadrails-6660beef367a888ac633cc03d1d7157737e6b2cb.tar.gz
rails-6660beef367a888ac633cc03d1d7157737e6b2cb.tar.bz2
rails-6660beef367a888ac633cc03d1d7157737e6b2cb.zip
An attempt to make CollectionAssociation#merge_target_lists make more sense.
Diffstat (limited to 'activerecord/lib/active_record/associations/collection_association.rb')
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb51
1 files changed, 35 insertions, 16 deletions
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 4429c655a2..d551cb01f0 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -387,25 +387,44 @@ module ActiveRecord
records
end
- def merge_target_lists(loaded, existing)
- return loaded if existing.empty?
- return existing if loaded.empty?
-
- loaded.map do |f|
- i = existing.index(f)
- if i
- existing.delete_at(i).tap do |t|
- keys = ["id"] + t.changes.keys + (f.attribute_names - t.attribute_names)
- # FIXME: this call to attributes causes many NoMethodErrors
- attributes = f.attributes
- (attributes.keys - keys).each do |k|
- t.send("#{k}=", attributes[k])
- end
+ # We have some records loaded from the database (persisted) and some that are
+ # in-memory (memory). The same record may be represented in the persisted array
+ # and in the memory array.
+ #
+ # So the task of this method is to merge them according to the following rules:
+ #
+ # * The final array must not have duplicates
+ # * The order of the persisted array is to be preserved
+ # * Any changes made to attributes on objects in the memory array are to be preserved
+ # * Otherwise, attributes should have the value found in the database
+ def merge_target_lists(persisted, memory)
+ return persisted if memory.empty?
+ return memory if persisted.empty?
+
+ persisted.map! do |record|
+ mem_record = memory.delete(record)
+
+ if mem_record
+ # FIXME: this call to record.attributes causes many NoMethodErrors
+ attributes = record.attributes
+
+ # Only try to assign attributes which exist on mem_record
+ shared = mem_record.attribute_names & attributes.keys
+
+ # Don't try to assign the primary key, or attributes which have changed on mem_record
+ excluded = ["id"] + mem_record.changes.keys
+
+ (shared - excluded).each do |key|
+ mem_record.send("#{key}=", attributes[key])
end
+
+ mem_record
else
- f
+ record
end
- end + existing
+ end
+
+ persisted + memory
end
# Do the relevant stuff to insert the given record into the association collection.