aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb42
-rw-r--r--activerecord/lib/active_record/base.rb11
2 files changed, 37 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..525ac65722 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -387,25 +387,35 @@ 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
+ (record.attribute_names - mem_record.changes.keys).each do |name|
+ mem_record[name] = record[name]
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.
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index e1bf2ccc8a..cd16b8d3ca 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -767,6 +767,17 @@ module ActiveRecord #:nodoc:
super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, '')))
end
+ # Returns an array of column names as strings if it's not
+ # an abstract class and table exists.
+ # Otherwise it returns an empty array.
+ def attribute_names
+ @attribute_names ||= if !abstract_class? && table_exists?
+ column_names
+ else
+ []
+ end
+ end
+
# Set the lookup ancestors for ActiveModel.
def lookup_ancestors #:nodoc:
klass = self