Class: ActiveRecord::Associations::AssociationCollection

Inherits:
AssociationProxy show all
Defined in:
lib/activerecord/lib/active_record/associations/association_collection.rb

Overview

:nodoc:

Direct Known Subclasses

HasManyAssociation

Instance Method Summary collapse

Instance Method Details

#<<(*records) ⇒ Object

Add records to this association. Returns self so method calls may be chained.

Since << flattens its argument list and inserts each record, push and concat behave identically.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/activerecord/lib/active_record/associations/association_collection.rb', line 53

def <<(*records)
  result = true
  load_target if @owner.new_record?

  @owner.transaction do
    flatten_deeper(records).each do |record|
      raise_on_type_mismatch(record)
      add_record_to_target_with_callbacks(record) do |r|
        result &&= insert_record(record) unless @owner.new_record?
      end
    end
  end

  @owner.send(:cache_write, @reflection, self) if @reflection.options[:cached]

  result && self
end

#clearObject

Removes all records from this association. Returns self so method calls may be chained.



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/activerecord/lib/active_record/associations/association_collection.rb', line 92

def clear
  return self if length.zero? # forces load_target if it hasn't happened already

  if @reflection.options[:dependent] && @reflection.options[:dependent] == :destroy
    destroy_all
  else
    delete_all
  end

  @owner.send(:cache_write, @reflection, self) if @reflection.options[:cached]

  self
end

#delete(*records) ⇒ Object

Remove records from this association. Does not destroy records.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/activerecord/lib/active_record/associations/association_collection.rb', line 72

def delete(*records)
  records = flatten_deeper(records)
  records.each { |record| raise_on_type_mismatch(record) }

  @owner.transaction do
    records.each { |record| callback(:before_remove, record) }

    old_records = records.reject {|r| r.new_record? }
    delete_records(old_records) if old_records.any?

    records.each do |record|
      @target.delete(record)
      callback(:after_remove, record)
    end
  end

  @owner.send(:cache_write, @reflection, self) if @reflection.options[:cached]
end

#find(*args) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/activerecord/lib/active_record/associations/association_collection.rb', line 6

def find(*args)
  options       = args.extract_options!
  expects_array = args.first.kind_of?(Array)
  args          = args.flatten.compact.uniq

  if @reflection.options[:cached] && !args.first.is_a?(Symbol)
    result = self.select { |record| args.map(&:to_i).include? record.id }
    return expects_array ? result : result.first
  end

  # If using a custom finder_sql, scan the entire collection.
  if @reflection.options[:finder_sql]
    ids = args.flatten.compact.uniq.map(&:to_i)
    if ids.size == 1
      id = ids.first
      record = load_target.detect { |r| id == r.id }
      expects_array ? [ record ] : record
    else
      load_target.select { |r| ids.include?(r.id) }
    end
  else
    conditions = "#{@finder_sql}"
    if sanitized_conditions = sanitize_sql(options[:conditions])
      conditions << " AND (#{sanitized_conditions})"
    end

    options[:conditions] = conditions

    if options[:order] && @reflection.options[:order]
      options[:order] = "#{options[:order]}, #{@reflection.options[:order]}"
    elsif @reflection.options[:order]
      options[:order] = @reflection.options[:order]
    end

    # Build options specific to association
    construct_find_options!(options)

    merge_options_from_reflection!(options)

    # Pass through args exactly as we received them.
    args << options
    @reflection.klass.find(*args)
  end
end

#sizeObject

Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn’t been loaded and calling collection.size if it has. If it’s more likely than not that the collection does have a size larger than zero and you need to fetch that collection afterwards, it’ll take one less SELECT query if you use length.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/activerecord/lib/active_record/associations/association_collection.rb', line 109

def size
  if @reflection.options[:cached]
    returning result = self.to_ary do
      @reflection.options[:uniq] ? result.uniq.size : result.size
    end
  end

  if @owner.new_record? || (loaded? && !@reflection.options[:uniq])
    @target.size
  elsif !loaded? && !@reflection.options[:uniq] && @target.is_a?(Array)
    unsaved_records = @target.select { |r| r.new_record? }
    unsaved_records.size + count_records
  else
    count_records
  end
end