diff options
Diffstat (limited to 'activerecord/lib/active_record/associations/collection_association.rb')
-rw-r--r-- | activerecord/lib/active_record/associations/collection_association.rb | 42 |
1 files changed, 27 insertions, 15 deletions
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index cec876149c..da4c311bce 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/array/wrap' - module ActiveRecord module Associations # = Active Record Association Collection @@ -49,17 +47,25 @@ module ActiveRecord end else column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}" + relation = scoped - scoped.select(column).map! do |record| - record.send(reflection.association_primary_key) + including = (relation.eager_load_values + relation.includes_values).uniq + + if including.any? + join_dependency = ActiveRecord::Associations::JoinDependency.new(reflection.klass, including, []) + relation = join_dependency.join_associations.inject(relation) do |r, association| + association.join_relation(r) + end end + + relation.pluck(column) end end # Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items def ids_writer(ids) pk_column = reflection.primary_key_column - ids = Array.wrap(ids).reject { |id| id.blank? } + ids = Array(ids).reject { |id| id.blank? } ids.map! { |i| pk_column.type_cast(i) } replace(klass.find(ids).index_by { |r| r.id }.values_at(*ids)) end @@ -152,6 +158,13 @@ module ActiveRecord end end + # Called when the association is declared as :dependent => :delete_all. This is + # an optimised version which avoids loading the records into memory. Not really + # for public consumption. + def delete_all_on_destroy + scoped.delete_all + end + # Destroy all the records from this association. # # See destroy for more info. @@ -235,7 +248,7 @@ module ActiveRecord # This method is abstract in the sense that it relies on # +count_records+, which is a method descendants have to provide. def size - if owner.new_record? || (loaded? && !options[:uniq]) + if !find_target? || (loaded? && !options[:uniq]) target.size elsif !loaded? && options[:group] load_target.size @@ -344,8 +357,12 @@ module ActiveRecord if options[:counter_sql] interpolate(options[:counter_sql]) else - # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */ - interpolate(options[:finder_sql]).sub(/SELECT\b(\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } + # replace the SELECT clause with COUNT(SELECTS), preserving any hints within /* ... */ + interpolate(options[:finder_sql]).sub(/SELECT\b(\/\*.*?\*\/ )?(.*)\bFROM\b/im) do + count_with = $2.to_s + count_with = '*' if count_with.blank? || count_with =~ /,/ + "SELECT #{$1}COUNT(#{count_with}) FROM" + end end end @@ -381,12 +398,7 @@ module ActiveRecord return memory if persisted.empty? persisted.map! do |record| - # Unfortunately we cannot simply do memory.delete(record) since on 1.8 this returns - # record rather than memory.at(memory.index(record)). The behavior is fixed in 1.9. - mem_index = memory.index(record) - - if mem_index - mem_record = memory.delete_at(mem_index) + if mem_record = memory.delete(record) (record.attribute_names - mem_record.changes.keys).each do |name| mem_record[name] = record[name] @@ -532,7 +544,7 @@ module ActiveRecord # If using a custom finder_sql, #find scans the entire collection. def find_by_scan(*args) expects_array = args.first.kind_of?(Array) - ids = args.flatten.compact.uniq.map { |arg| arg.to_i } + ids = args.flatten.compact.map{ |arg| arg.to_i }.uniq if ids.size == 1 id = ids.first |