diff options
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/associations/collection_association.rb | 42 | ||||
-rw-r--r-- | activerecord/lib/active_record/base.rb | 11 |
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 |