Class: ActiveRecord::Associations::AssociationCollection

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

Overview

:nodoc:

Instance Attribute Summary

Attributes inherited from AssociationProxy

#reflection

Instance Method Summary collapse

Methods inherited from AssociationProxy

#===, #aliased_table_name, #conditions, #initialize, #inspect, #loaded, #loaded?, #proxy_owner, #proxy_reflection, #proxy_respond_to?, #proxy_target, #reload, #respond_to?, #target, #target=

Constructor Details

This class inherits a constructor from ActiveRecord::Associations::AssociationProxy

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object (protected)



160
161
162
163
164
165
166
# File 'lib/active_record/associations/association_collection.rb', line 160

def method_missing(method, *args, &block)
  if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
    super
  else
    @reflection.klass.send(:with_scope, construct_scope) { @reflection.klass.send(method, *args, &block) }
  end
end

Instance Method Details

#<<(*records) ⇒ Object Also known as: push, concat

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.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/active_record/associations/association_collection.rb', line 18

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

  @owner.transaction do
    flatten_deeper(records).each do |record|
      raise_on_type_mismatch(record)
      callback(:before_add, record)
      result &&= insert_record(record) unless @owner.new_record?
      @target << record
      callback(:after_add, record)
    end
  end

  result && self
end

#any?(&block) ⇒ Boolean

Returns:

  • (Boolean)


124
125
126
127
128
129
130
# File 'lib/active_record/associations/association_collection.rb', line 124

def any?(&block)
  if block_given?
    method_missing(:any?, &block)
  else
    !empty?
  end
end

#clearObject

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



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/active_record/associations/association_collection.rb', line 68

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

  self
end

#create(attrs = {}) ⇒ Object



88
89
90
91
92
93
94
# File 'lib/active_record/associations/association_collection.rb', line 88

def create(attrs = {})
  if attrs.is_a?(Array)
    attrs.collect { |attr| create(attr) }
  else
    create_record(attrs) { |record| record.save }
  end
end

#create!(attrs = {}) ⇒ Object



96
97
98
# File 'lib/active_record/associations/association_collection.rb', line 96

def create!(attrs = {})
  create_record(attrs) { |record| record.save! }
end

#delete(*records) ⇒ Object

Remove records from this association. Does not destroy records.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/active_record/associations/association_collection.rb', line 51

def delete(*records)
  records = flatten_deeper(records)
  records.each { |record| raise_on_type_mismatch(record) }
  records.reject! { |record| @target.delete(record) if record.new_record? }
  return if records.empty?
  
  @owner.transaction do
    records.each { |record| callback(:before_remove, record) }
    delete_records(records)
    records.each do |record|
      @target.delete(record)
      callback(:after_remove, record)
    end
  end
end

#delete_allObject

Remove all records from this association



39
40
41
42
43
# File 'lib/active_record/associations/association_collection.rb', line 39

def delete_all
  load_target
  delete(@target)
  reset_target!
end

#destroy_allObject



80
81
82
83
84
85
86
# File 'lib/active_record/associations/association_collection.rb', line 80

def destroy_all
  @owner.transaction do
    each { |record| record.destroy }
  end

  reset_target!
end

#empty?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/active_record/associations/association_collection.rb', line 120

def empty?
  size.zero?
end

#lengthObject

Returns the size of the collection by loading it and calling size on the array. If you want to use this method to check whether the collection is empty, use collection.length.zero? instead of collection.empty?



116
117
118
# File 'lib/active_record/associations/association_collection.rb', line 116

def length
  load_target.size
end

#replace(other_array) ⇒ Object

Replace this collection with other_array This will perform a diff and delete/add only records that have changed.



145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/active_record/associations/association_collection.rb', line 145

def replace(other_array)
  other_array.each { |val| raise_on_type_mismatch(val) }

  load_target
  other   = other_array.size < 100 ? other_array : other_array.to_set
  current = @target.size < 100 ? @target : @target.to_set

  @owner.transaction do
    delete(@target.select { |v| !other.include?(v) })
    concat(other_array.select { |v| !current.include?(v) })
  end
end

#resetObject



11
12
13
14
# File 'lib/active_record/associations/association_collection.rb', line 11

def reset
  reset_target!
  @loaded = false
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.



103
104
105
106
107
108
109
110
111
112
# File 'lib/active_record/associations/association_collection.rb', line 103

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

#sum(*args, &block) ⇒ Object

Calculate sum using SQL, not Enumerable



46
47
48
# File 'lib/active_record/associations/association_collection.rb', line 46

def sum(*args, &block)
  calculate(:sum, *args, &block)
end

#to_aryObject



6
7
8
9
# File 'lib/active_record/associations/association_collection.rb', line 6

def to_ary
  load_target
  @target.to_ary
end

#uniq(collection = self) ⇒ Object



132
133
134
135
136
137
138
139
140
141
# File 'lib/active_record/associations/association_collection.rb', line 132

def uniq(collection = self)
  seen = Set.new
  collection.inject([]) do |kept, record|
    unless seen.include?(record.id)
      kept << record
      seen << record.id
    end
    kept
  end
end