Class: ActiveRecord::Associations::CollectionProxy
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
::ActiveRecord::Relation
|
|
Instance Chain:
|
|
Inherits: |
ActiveRecord::Relation
|
Defined in: | activerecord/lib/active_record/associations/collection_proxy.rb |
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
::ActiveRecord::Relation
- Inherited
CLAUSE_METHODS, INVALID_METHODS_FOR_DELETE_ALL, MULTI_VALUE_METHODS, SINGLE_VALUE_METHODS, VALUE_METHODS
Class Method Summary
::ActiveRecord::Relation
- Inherited
Instance Attribute Summary
-
#empty? ⇒ Boolean
readonly
Returns
true
if the collection is empty. -
#loaded
readonly
Alias for #loaded?.
::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, | |
#loaded? | Alias for Relation#loaded. |
#many? | Returns true if there is more than one record. |
#model | Alias for Relation#klass. |
#predicate_builder, | |
#scheduled? | Returns |
#skip_preloading_value, #table |
::Enumerable
- Included
#many? | Returns |
Instance Method Summary
-
#<<(*records)
(also: #push, #append, #concat)
Adds one or more #records to the collection by setting their foreign keys to the association’s primary key.
-
#==(other)
Equivalent to
Array#==
. -
#any?
Returns
true
if the collection is not empty. -
#append(*records)
Alias for #<<.
-
#build(attributes = {}, &block)
(also: #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. -
#calculate(operation, column_name)
–.
-
#clear
Equivalent to #delete_all.
-
#concat(*records)
Alias for #<<.
-
#count(column_name = nil, &block)
Count all records.
-
#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).
-
#create!(attributes = {}, &block)
Like #create, except that if the record is invalid, raises an exception.
-
#delete(*records)
Deletes the #records supplied from the collection according to the strategy specified by the
:dependent
option. -
#delete_all(dependent = nil)
Deletes all the records from the collection according to the strategy specified by the
:dependent
option. -
#destroy(*records)
Destroys the #records supplied and removes them from the collection.
-
#destroy_all
Deletes the records of the collection directly from the database ignoring the
:dependent
option. -
#distinct(value = true)
Specifies whether the records should be unique or not.
-
#fifth
Same as #first except returns only the fifth record.
-
#find(*args)
Finds an object in the collection responding to the
id
. -
#first(limit = nil)
Returns the first record, or the first
n
records, from the collection. -
#forty_two
Same as #first except returns only the forty second record.
-
#fourth
Same as #first except returns only the fourth record.
-
#include?(record) ⇒ Boolean
Returns
true
if the givenrecord
is present in the collection. -
#last(limit = nil)
Returns the last record, or the last
n
records, from the collection. -
#length
Returns the size of the collection calling #size on the target.
- #load_target
-
#loaded? ⇒ Boolean
(also: #loaded)
readonly
Returns
true
if the association has been loaded, otherwisefalse
. -
#many?
Returns true if the collection has more than one record.
-
#new(attributes = {}, &block)
Alias for #build.
- #pluck(*column_names)
-
#push(*records)
Alias for #<<.
-
#reload
Reloads the collection from the database.
-
#replace(other_array)
Replaces this collection with
other_array
. -
#reset
Unloads the association.
-
#scope
Returns a
::ActiveRecord::Relation
object for the records in this association. -
#second
Same as #first except returns only the second record.
-
#second_to_last
Same as #last except returns only the second-to-last record.
-
#select(*fields, &block)
Works in two ways.
-
#size
Returns the size of the collection.
-
#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
. - #target
-
#third
Same as #first except returns only the third record.
-
#third_to_last
Same as #last except returns only the third-to-last record.
-
#to_ary ⇒ ?
Returns a new array of objects from the collection.
::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! | |
#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 |
#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_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 |
#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_initialize_by | Like |
#initialize_copy, #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 |
#to_sql | Returns sql statement for the relation. |
#touch_all | Touches all records in the current relation, setting the |
#update_all | Updates all records in the current relation with details given. |
#update_counters | Updates the counters of the records in the current relation. |
#values |
::ActiveRecord::FinderMethods
- Included
#exists? | Returns true if a record exists in the table that matches the |
#fifth | Find the fifth record. |
#fifth! | Same as #fifth but raises |
#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_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 |
#forty_two | Find the forty-second record. |
#forty_two! | Same as #forty_two but raises |
#fourth | Find the fourth record. |
#fourth! | Same as #fourth but raises |
#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 |
#member? | Alias for FinderMethods#include?. |
#second | Find the second record. |
#second! | Same as #second but raises |
#second_to_last | Find the second-to-last record. |
#second_to_last! | Same as #second_to_last but raises |
#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 |
#third | Find the third record. |
#third! | Same as #third but raises |
#third_to_last | Find the third-to-last record. |
#third_to_last! | Same as #third_to_last but raises |
::ActiveRecord::Calculations
- Included
#async_average | Same as |
#async_count | Same as #count, but performs the query asynchronously and returns an |
#async_ids | Same as |
#async_maximum | Same as |
#async_minimum | Same as |
#async_pick | Same as |
#async_pluck | Same as #pluck, but performs the query asynchronously and returns an |
#async_sum | Same as |
#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 |
#merge | Merges in the conditions from |
#only | Removes any condition from the query other than the one(s) specified in |
::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 |
#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 | Allows to specify an order by a specific set of values. |
#includes | Specify associations |
#invert_where | Allows you to invert an entire where clause instead of manually applying conditions. |
#joins | Performs JOINs on |
#left_joins | Alias for QueryMethods#left_outer_joins. |
#left_outer_joins | Performs LEFT OUTER JOINs on |
#limit | Specifies a limit for the number of records to retrieve. |
#lock | Specifies locking settings (default to |
#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 |
#preload | Specify associations |
#readonly | Mark a relation as readonly. |
#references | Use to indicate that the given |
#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 |
#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. |
#without | Alias for QueryMethods#excluding. |
::ActiveRecord::Batches
- Included
#find_each | Looping through a collection of records from the database (using the |
#find_in_batches | Yields each batch of records that was found by the find options as an array. |
#in_batches | Yields |
::Enumerable
- Included
#compact_blank | Returns a new |
#exclude? | The negative of the |
#excluding | Returns a copy of the enumerable excluding the specified elements. |
#in_order_of | Returns a new |
#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 | Alias for Enumerable#excluding. |
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
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 831
def empty? @association.empty? end
#loaded (readonly)
Alias for #loaded?.
# 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>
# ]
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1036
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
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 967
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
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 836
rdoc_method :method: any?
#append(*records)
Alias for #<<.
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1040
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
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 318
def build(attributes = {}, &block) @association.build(attributes, &block) end
#calculate(operation, column_name)
–
# 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.
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1053
def clear delete_all self end
#concat(*records)
Alias for #<<.
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1041
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
# 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>
# ]
# 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
# 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>
# ]
# 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)
# 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)
# 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
# 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">
# ]
# 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.
# 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>
# ]
# 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) # => []
# 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”.
# 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.
# 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
# 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) # => []
# 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>
# ]
# 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
# 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
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 877
rdoc_method :method: many?
#new(attributes = {}, &block)
Alias for #build.
# 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
#push(*records)
Alias for #<<.
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1039
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>]
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1072
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
# 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>]
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1093
def reset proxy_association.reset proxy_association.reset_scope reset_scope end
#scope
Returns a ::ActiveRecord::Relation
object for the records in this association
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 936
def scope @scope ||= @association.scope end
#second
Same as #first except returns only the second record.
# 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.
# 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>
# ]
# 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.
# 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) # => []
# 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.
# 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.
# 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>
# ]
# File 'activerecord/lib/active_record/associations/collection_proxy.rb', line 1011
RDoc directive :method: to_ary