class ActiveRecord::Associations::CollectionAssociation

def size

+count_records+, which is a method descendants have to provide.
This method is abstract in the sense that it relies on

+length+ will take one less query. Otherwise +size+ is more efficient.
equivalent. If not and you are going to need the records anyway
If the collection has been already loaded +size+ and +length+ are

collection.size if it has.
query if the collection hasn't been loaded, and calling
Returns the size of the collection by executing a SELECT COUNT(*)
def size
  if !find_target? || loaded?
    target.size
  elsif @association_ids
    @association_ids.size
  elsif !association_scope.group_values.empty?
    load_target.size
  elsif !association_scope.distinct_value && !target.empty?
    unsaved_records = target.select(&:new_record?)
    unsaved_records.size + count_records
  else
    count_records
  end
end