123456789_123456789_123456789_123456789_123456789_

Class: ActiveRecord::Associations::CollectionProxy

Overview

Active Record Collection Proxy

Collection proxies in Active Record are middlemen between an #association, and its #target result set.

For example, given

class Blog < ActiveRecord::Base
  has_many :posts
end

blog = Blog.first

The collection proxy returned by blog.posts is built from a :has_many #association, and delegates to a collection of posts as the #target.

This class delegates unknown methods to the #association‘s relation class via a delegate cache.

The #target result set is not loaded until needed. For example,

blog.posts.count

is computed directly through SQL and does not trigger by itself the instantiation of the actual post records.

Constant Summary

::ActiveRecord::Batches - Included

DEFAULT_ORDER, ORDER_IGNORE_MESSAGE

::ActiveRecord::QueryMethods - Included

FROZEN_EMPTY_ARRAY, FROZEN_EMPTY_HASH, VALID_UNSCOPING_VALUES

::ActiveRecord::FinderMethods - Included

ONE_AS_ONE

::ActiveRecord::Relation - Inherited

CLAUSE_METHODS, INVALID_METHODS_FOR_DELETE_ALL, MULTI_VALUE_METHODS, SINGLE_VALUE_METHODS, VALUE_METHODS

Class Method Summary

Instance Attribute Summary

::ActiveRecord::Relation - Inherited

#blank?

Returns true if relation is blank.

#eager_loading?

Returns true if relation needs eager loading.

#empty?

Returns true if there are no records.

#klass

Alias for Relation#model.

#loaded?

Alias for Relation#loaded.

#many?

Returns true if there is more than one record.

#model, #predicate_builder, #readonly?,
#scheduled?

Returns true if the relation was scheduled on the background thread pool.

#skip_preloading_value, #table

::Enumerable - Included

#many?

Returns true if the enumerable has more than 1 element.

Instance Method Summary

::ActiveRecord::Relation - Inherited

#==

Compares two relations for equality.

#any?

Returns true if there are any records.

#build

Alias for Relation#new.

#cache_key

Returns a stable cache key that can be used to identify this query.

#cache_key_with_version

Returns a cache key along with the version.

#cache_version

Returns a cache version that can be used together with the cache key to form a recyclable caching scheme.

#create

Tries to create a new record with the same scoped attributes defined in the relation.

#create!

Similar to #create, but calls create! on the base class.

#create_or_find_by

Attempts to create a record with the given attributes in a table that has a unique database constraint on one or several of its columns.

#create_or_find_by!

Like #create_or_find_by, but calls create! so an exception is raised if the created record is invalid.

#delete

Deletes the row with a primary key matching the id argument, using an SQL DELETE statement, and returns the number of rows deleted.

#delete_all

Deletes the records without instantiating the records first, and hence not calling the #destroy method nor invoking callbacks.

#delete_by

Finds and deletes all records matching the specified conditions.

#destroy

Destroy an object (or multiple objects) that has the given id.

#destroy_all

Destroys the records by instantiating each record and calling its #destroy method.

#destroy_by

Finds and destroys all records matching the specified conditions.

#encode_with

Serializes the relation objects ::Array.

#explain

Runs EXPLAIN on the query or queries triggered by this relation and returns the result as a string.

#find_or_create_by

Finds the first record with the given attributes, or creates a record with the attributes if one is not found:

#find_or_create_by!

Like #find_or_create_by, but calls create! so an exception is raised if the created record is invalid.

#find_or_initialize_by

Like #find_or_create_by, but calls new instead of create.

#initialize_copy,
#insert

Inserts a single record into the database in a single SQL INSERT statement.

#insert!

Inserts a single record into the database in a single SQL INSERT statement.

#insert_all

Inserts multiple records into the database in a single SQL INSERT statement.

#insert_all!

Inserts multiple records into the database in a single SQL INSERT statement.

#inspect,
#joined_includes_values

Joins that are also marked for preloading.

#load

Causes the records to be loaded from the database if they have not been loaded already.

#load_async

Schedule the query to be performed from a background thread pool.

#loaded, #locked?,
#new

Initializes new record from relation while maintaining the current scope.

#none?

Returns true if there are no records.

#one?

Returns true if there is exactly one record.

#pretty_print,
#reload

Forces reloading of relation.

#reset, #scope_for_create,
#scoping

Scope all queries to the current scope.

#size

Returns size of the records.

#to_a

Alias for Relation#to_ary.

#to_ary

Converts relation objects to ::Array.

#to_sql

Returns sql statement for the relation.

#touch_all

Touches all records in the current relation, setting the updated_at+/+updated_on attributes to the current time or the time specified.

#update_all

Updates all records in the current relation with details given.

#update_counters

Updates the counters of the records in the current relation.

#upsert

Updates or inserts (upserts) a single record into the database in a single SQL INSERT statement.

#upsert_all

Updates or inserts (upserts) multiple records into the database in a single SQL INSERT statement.

#values

::ActiveRecord::TokenFor::RelationMethods - Included

#find_by_token_for

Finds a record using a given token for a predefined purpose.

#find_by_token_for!

Finds a record using a given token for a predefined purpose.

::ActiveRecord::FinderMethods - Included

#exists?

Returns true if a record exists in the table that matches the id or conditions given, or false otherwise.

#fifth

Find the fifth record.

#fifth!

Same as #fifth but raises ::ActiveRecord::RecordNotFound if no record is found.

#find

Find by id - This can either be a specific id (ID), a list of ids (ID, ID, ID), or an array of ids ([ID, ID, ID]).

#find_by

Finds the first record matching the specified conditions.

#find_by!

Like #find_by, except that if no record is found, raises an ::ActiveRecord::RecordNotFound error.

#find_sole_by

Finds the sole matching record.

#first

Find the first record (or first N records if a parameter is supplied).

#first!

Same as #first but raises ::ActiveRecord::RecordNotFound if no record is found.

#forty_two

Find the forty-second record.

#forty_two!

Same as #forty_two but raises ::ActiveRecord::RecordNotFound if no record is found.

#fourth

Find the fourth record.

#fourth!

Same as #fourth but raises ::ActiveRecord::RecordNotFound if no record is found.

#include?

Returns true if the relation contains the given record or false otherwise.

#last

Find the last record (or last N records if a parameter is supplied).

#last!

Same as #last but raises ::ActiveRecord::RecordNotFound if no record is found.

#member?
#second

Find the second record.

#second!

Same as #second but raises ::ActiveRecord::RecordNotFound if no record is found.

#second_to_last

Find the second-to-last record.

#second_to_last!

Same as #second_to_last but raises ::ActiveRecord::RecordNotFound if no record is found.

#sole

Finds the sole matching record.

#take

Gives a record (or N records if a parameter is supplied) without any implied order.

#take!

Same as #take but raises ::ActiveRecord::RecordNotFound if no record is found.

#third

Find the third record.

#third!

Same as #third but raises ::ActiveRecord::RecordNotFound if no record is found.

#third_to_last

Find the third-to-last record.

#third_to_last!

Same as #third_to_last but raises ::ActiveRecord::RecordNotFound if no record is found.

::ActiveRecord::Calculations - Included

#async_average

Same as #average, but performs the query asynchronously and returns an ::ActiveRecord::Promise.

#async_count

Same as #count, but performs the query asynchronously and returns an ::ActiveRecord::Promise.

#async_ids

Same as #ids, but performs the query asynchronously and returns an ::ActiveRecord::Promise.

#async_maximum

Same as #maximum, but performs the query asynchronously and returns an ::ActiveRecord::Promise.

#async_minimum

Same as #minimum, but performs the query asynchronously and returns an ::ActiveRecord::Promise.

#async_pick

Same as #pick, but performs the query asynchronously and returns an ::ActiveRecord::Promise.

#async_pluck

Same as #pluck, but performs the query asynchronously and returns an ::ActiveRecord::Promise.

#async_sum

Same as #sum, but performs the query asynchronously and returns an ::ActiveRecord::Promise.

#average

Calculates the average value on a given column.

#calculate

This calculates aggregate values in the given column.

#count

Count the records.

#ids

Returns the base model’s ID’s for the relation using the table’s primary key.

#maximum

Calculates the maximum value on a given column.

#minimum

Calculates the minimum value on a given column.

#pick

Pick the value(s) from the named column(s) in the current relation.

#pluck

Use #pluck as a shortcut to select one or more attributes without loading an entire record object per row.

#sum

Calculates the sum of values on a given column.

::ActiveRecord::SpawnMethods - Included

#except

Removes from the query the condition(s) specified in skips.

#merge

Merges in the conditions from other, if other is an ::ActiveRecord::Relation.

#only

Removes any condition from the query other than the one(s) specified in onlies.

::ActiveRecord::QueryMethods - Included

#and

Returns a new relation, which is the logical intersection of this relation and the one passed as an argument.

#annotate

Adds an SQL comment to queries generated from this relation.

#create_with

Sets attributes to be used when creating new records from a relation object.

#distinct

Specifies whether the records should be unique or not.

#eager_load

Specify associations args to be eager loaded using a LEFT OUTER JOIN.

#excluding

Excludes the specified record (or collection of records) from the resulting relation.

#extending

Used to extend a scope with additional methods, either through a module or through a block provided.

#extensions,
#extract_associated

Extracts a named #association from the relation.

#from

Specifies the table from which the records will be fetched.

#group

Allows to specify a group attribute:

#having

Allows to specify a HAVING clause.

#in_order_of

Applies an ORDER BY clause based on a given column, ordered and filtered by a specific set of values.

#includes

Specify associations args to be eager loaded to prevent N + 1 queries.

#invert_where

Allows you to invert an entire where clause instead of manually applying conditions.

#joins

Performs JOINs on args.

#left_joins
#left_outer_joins

Performs LEFT OUTER JOINs on args:

#limit

Specifies a limit for the number of records to retrieve.

#lock

Specifies locking settings (default to true).

#none

Returns a chainable relation with zero records.

#offset

Specifies the number of rows to skip before returning rows.

#optimizer_hints

Specify optimizer hints to be used in the SELECT statement.

#or

Returns a new relation, which is the logical union of this relation and the one passed as an argument.

#order

Applies an ORDER BY clause to a query.

#preload

Specify associations args to be eager loaded using separate queries.

#readonly

Mark a relation as readonly.

#references

Use to indicate that the given table_names are referenced by an SQL string, and should therefore be JOINed in any query rather than loaded separately.

#regroup

Allows you to change a previously set group statement.

#reorder

Replaces any existing order defined on the relation with the specified order.

#reselect

Allows you to change a previously set select statement.

#reverse_order

Reverse the existing order clause on the relation.

#rewhere

Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.

#select

Works in two unique ways.

#strict_loading

Sets the returned relation to strict_loading mode.

#structurally_compatible?

Checks whether the given relation is structurally compatible with this relation, to determine if it’s possible to use the #and and #or methods without raising an error.

#uniq!

Deduplicate multiple values.

#unscope

Removes an unwanted relation that is already defined on a chain of relations.

#where

Returns a new relation, which is the result of filtering the current relation according to the conditions in the arguments.

#with

Add a Common Table Expression (CTE) that you can then reference within another SELECT statement.

#with_recursive

Add a recursive Common Table Expression (CTE) that you can then reference within another SELECT statement.

#without

::ActiveRecord::Batches - Included

#find_each

Looping through a collection of records from the database (using the Scoping::Named::ClassMethods.all method, for example) is very inefficient since it will try to instantiate all the objects at once.

#find_in_batches

Yields each batch of records that was found by the find options as an array.

#in_batches

Yields ::ActiveRecord::Relation objects to work with a batch of records.

::Enumerable - Included

#compact_blank

Returns a new ::Array without the blank items.

#exclude?

The negative of the Enumerable#include?.

#excluding

Returns a copy of the enumerable excluding the specified elements.

#in_order_of

Returns a new ::Array where the order has been set to that provided in the series, based on the key of the objects in the original enumerable.

#including

Returns a new array that includes the passed elements.

#index_by

Convert an enumerable to a hash, using the block result as the key and the element as the value.

#index_with

Convert an enumerable to a hash, using the element as the key and the block result as the value.

#maximum

Calculates the maximum from the extracted elements.

#minimum

Calculates the minimum from the extracted elements.

#pick

Extract the given key from the first element in the enumerable.

#pluck

Extract the given key from each element in the enumerable.

#sole

Returns the sole item in the enumerable.

#without

Constructor Details

This class inherits a constructor from ActiveRecord::Relation

Instance Attribute Details

#empty?Boolean (readonly)

Returns true if the collection is empty. If the collection has been loaded it is equivalent to collection.size.zero?. If the collection has not been loaded, it is equivalent to !collection.exists?. If the collection has not already been loaded and you are going to fetch the records anyway it is better to check collection.load.empty?.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.count  # => 1
person.pets.empty? # => false

person.pets.delete_all

person.pets.count  # => 0
person.pets.empty? # => true
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 831

def empty?
  @association.empty?
end

#loaded (readonly)

Alias for #loaded?.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 56

alias :loaded :loaded?

Instance Method Details

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

Adds one or more #records to the collection by setting their foreign keys to the association’s primary key. Since << flattens its argument list and inserts each record, #push and #concat behave identically. Returns self so several appends may be chained together.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.size # => 0
person.pets << Pet.new(name: 'Fancy-Fancy')
person.pets << [Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo')]
person.pets.size # => 3

person.id # => 1
person.pets
# => [
#      #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#      #<Pet id: 2, name: "Spook", person_id: 1>,
#      #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1049

def <<(*records)
  proxy_association.concat(records) && self
end

#==(other)

Equivalent to Array#==. Returns true if the two arrays contain the same number of elements and if each element is equal to the corresponding element in the other array, otherwise returns false.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets
# => [
#      #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#      #<Pet id: 2, name: "Spook", person_id: 1>
#    ]

other = person.pets.to_ary

person.pets == other
# => true

Note that unpersisted records can still be seen as equal:

other = [Pet.new(id: 1), Pet.new(id: 2)]

person.pets == other
# => true
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 980

def ==(other)
  load_target == other
end

#any?

Returns true if the collection is not empty.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.count # => 0
person.pets.any?  # => false

person.pets << Pet.new(name: 'Snoop')
person.pets.count # => 1
person.pets.any?  # => true

Calling it without a block when the collection is not yet loaded is equivalent to collection.exists?. If you’re going to load the collection anyway, it is better to call collection.load.any? to avoid an extra query.

You can also pass a block to define criteria. The behavior is the same, it returns true if the collection based on the criteria is not empty.

person.pets
# => [#<Pet name: "Snoop", group: "dogs">]

person.pets.any? do |pet|
  pet.group == 'cats'
end
# => false

person.pets.any? do |pet|
  pet.group == 'dogs'
end
# => true
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 836

rdoc_method :method: any?

#append(*records)

Alias for #<<.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1053

alias_method :append, :<<

#build(attributes = {}, &block) Also known as: #new

Returns a new object of the collection type that has been instantiated with attributes and linked to this object, but have not yet been saved. You can pass an array of attributes hashes, this will return an array with the new objects.

class Person
  has_many :pets
end

person.pets.build
# => #<Pet id: nil, name: nil, person_id: 1>

person.pets.build(name: 'Fancy-Fancy')
# => #<Pet id: nil, name: "Fancy-Fancy", person_id: 1>

person.pets.build([{name: 'Spook'}, {name: 'Choo-Choo'}, {name: 'Brain'}])
# => [
#      #<Pet id: nil, name: "Spook", person_id: 1>,
#      #<Pet id: nil, name: "Choo-Choo", person_id: 1>,
#      #<Pet id: nil, name: "Brain", person_id: 1>
#    ]

person.pets.size  # => 5 # size of the collection
person.pets.count # => 0 # count from database
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 318

def build(attributes = {}, &block)
  @association.build(attributes, &block)
end

#calculate(operation, column_name)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 724

def calculate(operation, column_name)
  null_scope? ? scope.calculate(operation, column_name) : super
end

#clear

Equivalent to #delete_all. The difference is that returns self, instead of an array with the deleted objects, so methods can be chained. See #delete_all for more information. Note that because #delete_all removes records by directly running an SQL query into the database, the updated_at column of the object is not changed.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1066

def clear
  delete_all
  self
end

#concat(*records)

Alias for #<<.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1054

alias_method :concat, :<<

#count(column_name = nil, &block)

Count all records.

class Person < ActiveRecord::Base
  has_many :pets
end

# This will perform the count using SQL.
person.pets.count # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

Passing a block will select all of a person’s pets in SQL and then perform the count using Ruby.

person.pets.count { |pet| pet.name.include?('-') } # => 2
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 733

rdoc_method :method: count

#create(attributes = {}, &block)

Returns a new object of the collection type that has been instantiated with attributes, linked to this object and that has already been saved (if it passes the validations).

class Person
  has_many :pets
end

person.pets.create(name: 'Fancy-Fancy')
# => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>

person.pets.create([{name: 'Spook'}, {name: 'Choo-Choo'}])
# => [
#      #<Pet id: 2, name: "Spook", person_id: 1>,
#      #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.size  # => 3
person.pets.count # => 3

person.pets.find(1, 2, 3)
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 349

def create(attributes = {}, &block)
  @association.create(attributes, &block)
end

#create!(attributes = {}, &block)

Like #create, except that if the record is invalid, raises an exception.

class Person
  has_many :pets
end

class Pet
  validates :name, presence: true
end

person.pets.create!(name: nil)
# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 365

def create!(attributes = {}, &block)
  @association.create!(attributes, &block)
end

#delete(*records)

Deletes the #records supplied from the collection according to the strategy specified by the :dependent option. If no :dependent option is given, then it will follow the default strategy. Returns an array with the deleted records.

For has_many :through associations, the default deletion strategy is :delete_all.

For has_many associations, the default deletion strategy is :nullify. This sets the foreign keys to NULL.

class Person < ActiveRecord::Base
  has_many :pets # dependent: :nullify option by default
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.delete(Pet.find(1))
# => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]

person.pets.size # => 2
person.pets
# => [
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

Pet.find(1)
# => #<Pet id: 1, name: "Fancy-Fancy", person_id: nil>

If it is set to :destroy all the #records are removed by calling their #destroy method. See #destroy for more information.

class Person < ActiveRecord::Base
  has_many :pets, dependent: :destroy
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.delete(Pet.find(1), Pet.find(3))
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.size # => 1
person.pets
# => [#<Pet id: 2, name: "Spook", person_id: 1>]

Pet.find(1, 3)
# => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 3)

If it is set to :delete_all, all the #records are deleted without calling their #destroy method.

class Person < ActiveRecord::Base
  has_many :pets, dependent: :delete_all
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.delete(Pet.find(1))
# => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]

person.pets.size # => 2
person.pets
# => [
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

Pet.find(1)
# => ActiveRecord::RecordNotFound: Couldn't find Pet with 'id'=1

You can pass ::Integer or ::String values, it finds the records responding to the id and executes delete on them.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.delete("1")
# => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]

person.pets.delete(2, 3)
# => [
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 620

def delete(*records)
  @association.delete(*records).tap { reset_scope }
end

#delete_all(dependent = nil)

Deletes all the records from the collection according to the strategy specified by the :dependent option. If no :dependent option is given, then it will follow the default strategy.

For has_many :through associations, the default deletion strategy is :delete_all.

For has_many associations, the default deletion strategy is :nullify. This sets the foreign keys to NULL.

class Person < ActiveRecord::Base
  has_many :pets # dependent: :nullify option by default
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.delete_all
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.size # => 0
person.pets      # => []

Pet.find(1, 2, 3)
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: nil>,
#       #<Pet id: 2, name: "Spook", person_id: nil>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: nil>
#    ]

Both has_many and has_many :through dependencies default to the :delete_all strategy if the :dependent option is set to :destroy. Records are not instantiated and callbacks will not be fired.

class Person < ActiveRecord::Base
  has_many :pets, dependent: :destroy
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.delete_all

Pet.find(1, 2, 3)
# => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)

If it is set to :delete_all, all the objects are deleted without calling their #destroy method.

class Person < ActiveRecord::Base
  has_many :pets, dependent: :delete_all
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.delete_all

Pet.find(1, 2, 3)
# => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 474

def delete_all(dependent = nil)
  @association.delete_all(dependent).tap { reset_scope }
end

#destroy(*records)

Destroys the #records supplied and removes them from the collection. This method will always remove record from the database ignoring the :dependent option. Returns an array with the removed records.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.destroy(Pet.find(1))
# => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]

person.pets.size # => 2
person.pets
# => [
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.destroy(Pet.find(2), Pet.find(3))
# => [
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.size  # => 0
person.pets       # => []

Pet.find(1, 2, 3) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)

You can pass ::Integer or ::String values, it finds the records responding to the id and then deletes them from the database.

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 4, name: "Benny", person_id: 1>,
#       #<Pet id: 5, name: "Brain", person_id: 1>,
#       #<Pet id: 6, name: "Boss",  person_id: 1>
#    ]

person.pets.destroy("4")
# => #<Pet id: 4, name: "Benny", person_id: 1>

person.pets.size # => 2
person.pets
# => [
#       #<Pet id: 5, name: "Brain", person_id: 1>,
#       #<Pet id: 6, name: "Boss",  person_id: 1>
#    ]

person.pets.destroy(5, 6)
# => [
#       #<Pet id: 5, name: "Brain", person_id: 1>,
#       #<Pet id: 6, name: "Boss",  person_id: 1>
#    ]

person.pets.size  # => 0
person.pets       # => []

Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (4, 5, 6)
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 692

def destroy(*records)
  @association.destroy(*records).tap { reset_scope }
end

#destroy_all

Deletes the records of the collection directly from the database ignoring the :dependent option. Records are instantiated and it invokes before_remove, after_remove, before_destroy, and after_destroy callbacks.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.size # => 3
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.destroy_all

person.pets.size # => 0
person.pets      # => []

Pet.find(1) # => Couldn't find Pet with id=1
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 501

def destroy_all
  @association.destroy_all.tap { reset_scope }
end

#distinct(value = true)

Specifies whether the records should be unique or not.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.select(:name)
# => [
#      #<Pet name: "Fancy-Fancy">,
#      #<Pet name: "Fancy-Fancy">
#    ]

person.pets.select(:name).distinct
# => [#<Pet name: "Fancy-Fancy">]

person.pets.select(:name).distinct.distinct(false)
# => [
#      #<Pet name: "Fancy-Fancy">,
#      #<Pet name: "Fancy-Fancy">
#    ]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 697

rdoc_method :method: distinct

#fifth

Same as #first except returns only the fifth record.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 201

rdoc_method :method: fifth

#find(*args)

Finds an object in the collection responding to the id. Uses the same rules as ActiveRecord::FinderMethods.find. Returns ::ActiveRecord::RecordNotFound error if the object cannot be found.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.find(1) # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
person.pets.find(4) # => ActiveRecord::RecordNotFound: Couldn't find Pet with 'id'=4

person.pets.find(2) { |pet| pet.name.downcase! }
# => #<Pet id: 2, name: "fancy-fancy", person_id: 1>

person.pets.find(2, 3)
# => [
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 138

def find(*args)
  return super if block_given?
  @association.find(*args)
end

#first(limit = nil)

Returns the first record, or the first n records, from the collection. If the collection is empty, the first form returns nil, and the second form returns an empty array.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.first # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>

person.pets.first(2)
# => [
#      #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#      #<Pet id: 2, name: "Spook", person_id: 1>
#    ]

another_person_without.pets          # => []
another_person_without.pets.first    # => nil
another_person_without.pets.first(3) # => []
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 144

rdoc_method :method: first

#forty_two

Same as #first except returns only the forty second record. Also known as accessing “the reddit”.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 209

rdoc_method :method: forty_two

#fourth

Same as #first except returns only the fourth record.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 193

rdoc_method :method: fourth

#include?(record) ⇒ Boolean

Returns true if the given record is present in the collection.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets # => [#<Pet id: 20, name: "Snoop">]

person.pets.include?(Pet.find(20)) # => true
person.pets.include?(Pet.find(21)) # => false
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 927

def include?(record)
  !!@association.include?(record)
end

#last(limit = nil)

Returns the last record, or the last n records, from the collection. If the collection is empty, the first form returns nil, and the second form returns an empty array.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.last # => #<Pet id: 3, name: "Choo-Choo", person_id: 1>

person.pets.last(2)
# => [
#      #<Pet id: 2, name: "Spook", person_id: 1>,
#      #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

another_person_without.pets         # => []
another_person_without.pets.last    # => nil
another_person_without.pets.last(3) # => []
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 259

def last(limit = nil)
  load_target if find_from_target?
  super
end

#length

Returns the size of the collection calling #size on the target. If the collection has been already loaded, length and #size are equivalent. If not and you are going to need the records anyway this method will take one less query. Otherwise #size is more efficient.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.length # => 3
# executes something like SELECT "pets".* FROM "pets" WHERE "pets"."person_id" = 1

# Because the collection is loaded, you can
# call the collection with no additional queries:
person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 787

rdoc_method :method: length

#load_target

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 44

def load_target
  @association.load_target
end

#loaded?Boolean (readonly) Also known as: #loaded

Returns true if the association has been loaded, otherwise false.

person.pets.loaded? # => false
person.pets.records
person.pets.loaded? # => true
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 53

def loaded?
  @association.loaded?
end

#many?

Returns true if the collection has more than one record. Equivalent to collection.size > 1.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.count # => 1
person.pets.many? # => false

person.pets << Pet.new(name: 'Snoopy')
person.pets.count # => 2
person.pets.many? # => true

You can also pass a block to define criteria. The behavior is the same, it returns true if the collection based on the criteria has more than one record.

person.pets
# => [
#      #<Pet name: "Gorby", group: "cats">,
#      #<Pet name: "Puff", group: "cats">,
#      #<Pet name: "Snoop", group: "dogs">
#    ]

person.pets.many? do |pet|
  pet.group == 'dogs'
end
# => false

person.pets.many? do |pet|
  pet.group == 'cats'
end
# => true
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 877

rdoc_method :method: many?

#new(attributes = {}, &block)

Alias for #build.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 321

alias_method :new, :build

#pluck(*column_names)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 728

def pluck(*column_names)
  null_scope? ? scope.pluck(*column_names) : super
end

#proxy_association

Returns the association object for the collection.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.proxy_association
# => #<ActiveRecord::Associations::HasManyAssociation owner="#<Person:0x00>">

Returns the same object as person.association(:pets), allowing you to make calls like person.pets.proxy_association.owner.

See Associations::ClassMethods@Association+extensions for more.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 944

def proxy_association
  @association
end

#push(*records)

Alias for #<<.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1052

alias_method :push, :<<

#reload

Reloads the collection from the database. Returns self.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets # fetches pets from the database
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]

person.pets # uses the pets cache
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]

person.pets.reload # fetches pets from the database
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1085

def reload
  proxy_association.reload(true)
  reset_scope
end

#replace(other_array)

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

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets
# => [#<Pet id: 1, name: "Gorby", group: "cats", person_id: 1>]

other_pets = [Pet.new(name: 'Puff', group: 'celebrities')]

person.pets.replace(other_pets)

person.pets
# => [#<Pet id: 2, name: "Puff", group: "celebrities", person_id: 1>]

If the supplied array has an incorrect association type, it raises an ::ActiveRecord::AssociationTypeMismatch error:

person.pets.replace(["doo", "ggie", "gaga"])
# => ActiveRecord::AssociationTypeMismatch: Pet expected, got String
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 391

def replace(other_array)
  @association.replace(other_array)
end

#reset

Unloads the association. Returns self.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets # fetches pets from the database
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]

person.pets # uses the pets cache
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]

person.pets.reset # clears the pets cache

person.pets  # fetches pets from the database
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1106

def reset
  proxy_association.reset
  proxy_association.reset_scope
  reset_scope
end

#scope

Returns a ::ActiveRecord::Relation object for the records in this association

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 949

def scope
  @scope ||= @association.scope
end

#second

Same as #first except returns only the second record.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 177

rdoc_method :method: second

#second_to_last

Same as #last except returns only the second-to-last record.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 226

rdoc_method :method: second_to_last

#select(*fields, &block)

Works in two ways.

First: Specify a subset of fields to be selected from the result set.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.select(:name)
# => [
#      #<Pet id: nil, name: "Fancy-Fancy">,
#      #<Pet id: nil, name: "Spook">,
#      #<Pet id: nil, name: "Choo-Choo">
#    ]

person.pets.select(:id, :name)
# => [
#      #<Pet id: 1, name: "Fancy-Fancy">,
#      #<Pet id: 2, name: "Spook">,
#      #<Pet id: 3, name: "Choo-Choo">
#    ]

Be careful because this also means you’re initializing a model object with only the fields that you’ve selected. If you attempt to access a field except id that is not in the initialized record you’ll receive:

person.pets.select(:name).first.person_id
# => ActiveModel::MissingAttributeError: missing attribute 'person_id' for Pet

Second: You can pass a block so it can be used just like Array#select. This builds an array of objects from the database for the scope, converting them into an array and iterating through them using Array#select.

person.pets.select { |pet| /oo/.match?(pet.name) }
# => [
#      #<Pet id: 2, name: "Spook", person_id: 1>,
#      #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 59

rdoc_method :method: select

#size

Returns the size of the collection. If the collection hasn’t been loaded, it executes a SELECT COUNT(*) query. Else it calls collection.size.

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

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets.size # => 3
# executes something like SELECT COUNT(*) FROM "pets" WHERE "pets"."person_id" = 1

person.pets # This will execute a SELECT * FROM query
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.size # => 3
# Because the collection is already loaded, this will behave like
# collection.size and no SQL count query is executed.
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 782

def size
  @association.size
end

#take(limit = nil)

Gives a record (or N records if a parameter is supplied) from the collection using the same rules as ActiveRecord::FinderMethods.take.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets
# => [
#       #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#       #<Pet id: 2, name: "Spook", person_id: 1>,
#       #<Pet id: 3, name: "Choo-Choo", person_id: 1>
#    ]

person.pets.take # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>

person.pets.take(2)
# => [
#      #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
#      #<Pet id: 2, name: "Spook", person_id: 1>
#    ]

another_person_without.pets         # => []
another_person_without.pets.take    # => nil
another_person_without.pets.take(2) # => []
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 289

def take(limit = nil)
  load_target if find_from_target?
  super
end

#target

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 40

def target
  @association.target
end

#third

Same as #first except returns only the third record.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 185

rdoc_method :method: third

#third_to_last

Same as #last except returns only the third-to-last record.

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 218

rdoc_method :method: third_to_last

#to_ary ⇒ ?

Returns a new array of objects from the collection. If the collection hasn’t been loaded, it fetches the records from the database.

class Person < ActiveRecord::Base
  has_many :pets
end

person.pets
# => [
#       #<Pet id: 4, name: "Benny", person_id: 1>,
#       #<Pet id: 5, name: "Brain", person_id: 1>,
#       #<Pet id: 6, name: "Boss",  person_id: 1>
#    ]

other_pets = person.pets.to_ary
# => [
#       #<Pet id: 4, name: "Benny", person_id: 1>,
#       #<Pet id: 5, name: "Brain", person_id: 1>,
#       #<Pet id: 6, name: "Boss",  person_id: 1>
#    ]

other_pets.replace([Pet.new(name: 'BooGoo')])

other_pets
# => [#<Pet id: nil, name: "BooGoo", person_id: 1>]

person.pets
# This is not affected by replace
# => [
#       #<Pet id: 4, name: "Benny", person_id: 1>,
#       #<Pet id: 5, name: "Brain", person_id: 1>,
#       #<Pet id: 6, name: "Boss",  person_id: 1>
#    ]
[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1024

RDoc directive :method: to_ary