Class: ActiveRecord::Associations::CollectionProxy
- Defined in:
- lib/active_record/associations/collection_proxy.rb
Overview
Association proxies in Active Record are middlemen between the object that holds the association, known as the @owner
, and the actual associated object, known as the @target
. The kind of association any proxy is about is available in @reflection
. That’s an instance of the class ActiveRecord::Reflection::AssociationReflection.
For example, given
class Blog < ActiveRecord::Base
has_many :posts
end
blog = Blog.first
the association proxy in blog.posts
has the object in blog
as @owner
, the collection of its posts as @target
, and the @reflection
object represents a :has_many
macro.
This class delegates unknown methods to @target
via method_missing
.
The @target
object 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
Constants inherited from Relation
Relation::MULTI_VALUE_METHODS, Relation::SINGLE_VALUE_METHODS, Relation::VALUE_METHODS
Constants included from QueryMethods
QueryMethods::VALID_UNSCOPING_VALUES
Instance Attribute Summary
Attributes inherited from Relation
#default_scoped, #klass, #loaded, #table
Instance Method Summary collapse
-
#<<(*records) ⇒ Object
(also: #push, #append)
Adds one or more
records
to the collection by setting their foreign keys to the association’s primary key. -
#==(other) ⇒ Object
Equivalent to
Array#==
. -
#any?(&block) ⇒ Boolean
Returns
true
if the collection is not empty. -
#build(attributes = {}, &block) ⇒ Object
(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. -
#clear ⇒ Object
Equivalent to
delete_all
. -
#concat(*records) ⇒ Object
Add one or more records to the collection by setting their foreign keys to the association’s primary key.
-
#count(column_name = nil, options = {}) ⇒ Object
Count all records using SQL.
-
#create(attributes = {}, &block) ⇒ Object
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) ⇒ Object
Like
create
, except that if the record is invalid, raises an exception. -
#delete(*records) ⇒ Object
Deletes the
records
supplied and removes them from the collection. -
#delete_all ⇒ Object
Deletes all the records from the collection.
-
#destroy(*records) ⇒ Object
Destroys the
records
supplied and removes them from the collection. -
#destroy_all ⇒ Object
Deletes the records of the collection directly from the database.
-
#distinct ⇒ Object
(also: #uniq)
Specifies whether the records should be unique or not.
-
#empty? ⇒ Boolean
Returns
true
if the collection is empty. -
#find(*args, &block) ⇒ Object
Finds an object in the collection responding to the
id
. -
#first(*args) ⇒ Object
Returns the first record, or the first
n
records, from the collection. -
#include?(record) ⇒ Boolean
Returns
true
if the given object is present in the collection. -
#initialize(klass, association) ⇒ CollectionProxy
constructor
:nodoc:.
-
#last(*args) ⇒ Object
Returns the last record, or the last
n
records, from the collection. -
#length ⇒ Object
Returns the size of the collection calling
size
on the target. - #load_target ⇒ Object
-
#loaded? ⇒ Boolean
Returns
true
if the association has been loaded, otherwisefalse
. -
#many?(&block) ⇒ Boolean
Returns true if the collection has more than one record.
- #prepend(*args) ⇒ Object
- #proxy_association ⇒ Object
-
#reload ⇒ Object
Reloads the collection from the database.
-
#replace(other_array) ⇒ Object
Replaces this collection with
other_array
. -
#scope ⇒ Object
(also: #spawn)
Returns a
Relation
object for the records in this association. -
#scoping ⇒ Object
We don’t want this object to be put on the scoping stack, because that could create an infinite loop where we call an @association method, which gets the current scope, which is this object, which delegates to @association, and so on.
-
#select(select = nil, &block) ⇒ Object
Works in two ways.
-
#size ⇒ Object
Returns the size of the collection.
- #target ⇒ Object
-
#to_ary ⇒ Object
(also: #to_a)
Returns a new array of objects from the collection.
Methods inherited from Relation
#as_json, #blank?, #eager_loading?, #explain, #find_or_create_by, #find_or_create_by!, #find_or_initialize_by, #first_or_create, #first_or_create!, #first_or_initialize, #initialize_copy, #insert, #inspect, #joined_includes_values, #load, #pretty_print, #reset, #scope_for_create, #to_sql, #uniq_value, #update, #update_all, #values, #where_values_hash, #with_default_scope
Methods included from FinderMethods
#exists?, #find_by, #find_by!, #first!, #last!, #raise_record_not_found_exception!, #take, #take!
Methods included from Calculations
#average, #calculate, #ids, #maximum, #minimum, #pluck, #sum
Methods included from SpawnMethods
#except, #merge, #merge!, #only
Methods included from QueryMethods
#arel, #bind, #bind!, #build_arel, #create_with, #create_with!, #create_with_value, #distinct!, #eager_load, #eager_load!, #extending, #extending!, #from, #from!, #group, #group!, #having, #having!, #includes, #includes!, #joins, #joins!, #limit, #limit!, #lock, #lock!, #none, #none!, #offset, #offset!, #order, #order!, #preload, #preload!, #readonly, #readonly!, #references, #references!, #reorder, #reorder!, #reverse_order, #reverse_order!, #select!, #unscope, #unscope!, #where, #where!
Methods included from Batches
Methods included from Explain
#collecting_queries_for_explain, #exec_explain
Methods included from Delegation
Constructor Details
#initialize(klass, association) ⇒ CollectionProxy
:nodoc:
33 34 35 36 37 38 |
# File 'lib/active_record/associations/collection_proxy.rb', line 33 def initialize(klass, association) #:nodoc: @association = association super klass, klass.arel_table self.default_scoped = true merge! association.scope(nullify: false) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class ActiveRecord::Delegation
Instance Method Details
#<<(*records) ⇒ Object Also known as: push, append
Adds one or more records
to the collection by setting their foreign keys to the association’s primary key. 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>
# ]
942 943 944 |
# File 'lib/active_record/associations/collection_proxy.rb', line 942 def <<(*records) proxy_association.concat(records) && self end |
#==(other) ⇒ Object
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
other = [Pet.new(id: 1), Pet.new(id: 2)]
person.pets == other
# => false
880 881 882 |
# File 'lib/active_record/associations/collection_proxy.rb', line 880 def ==(other) load_target == other end |
#any?(&block) ⇒ Boolean
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 # => 0
person.pets.any? # => 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 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
780 781 782 |
# File 'lib/active_record/associations/collection_proxy.rb', line 780 def any?(&block) @association.any?(&block) end |
#build(attributes = {}, &block) ⇒ Object 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
228 229 230 |
# File 'lib/active_record/associations/collection_proxy.rb', line 228 def build(attributes = {}, &block) @association.build(attributes, &block) end |
#clear ⇒ Object
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.
955 956 957 958 |
# File 'lib/active_record/associations/collection_proxy.rb', line 955 def clear delete_all self end |
#concat(*records) ⇒ Object
Add 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 method calls may be chained.
class Person < ActiveRecord::Base
has_many :pets
end
person.pets.size # => 0
person.pets.concat(Pet.new(name: 'Fancy-Fancy'))
person.pets.concat(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>
# ]
person.pets.concat([Pet.new(name: 'Brain'), Pet.new(name: 'Benny')])
person.pets.size # => 5
303 304 305 |
# File 'lib/active_record/associations/collection_proxy.rb', line 303 def concat(*records) @association.concat(*records) end |
#count(column_name = nil, options = {}) ⇒ Object
Count all records using SQL.
class Person < ActiveRecord::Base
has_many :pets
end
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>
# ]
673 674 675 |
# File 'lib/active_record/associations/collection_proxy.rb', line 673 def count(column_name = nil, = {}) @association.count(column_name, ) end |
#create(attributes = {}, &block) ⇒ Object
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>
# ]
259 260 261 |
# File 'lib/active_record/associations/collection_proxy.rb', line 259 def create(attributes = {}, &block) @association.create(attributes, &block) end |
#create!(attributes = {}, &block) ⇒ Object
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
275 276 277 |
# File 'lib/active_record/associations/collection_proxy.rb', line 275 def create!(attributes = {}, &block) @association.create!(attributes, &block) end |
#delete(*records) ⇒ Object
Deletes the records
supplied and removes them from the collection. For has_many
associations, the deletion is done according to the strategy specified by the :dependent
option. Returns an array with the deleted records.
If no :dependent
option is given, then it will follow the default strategy. The default strategy is :nullify
. This sets the foreign keys to NULL
. For, has_many
:through
, the default strategy is delete_all
.
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 IDs (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 Fixnum
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>
# ]
565 566 567 |
# File 'lib/active_record/associations/collection_proxy.rb', line 565 def delete(*records) @association.delete(*records) end |
#delete_all ⇒ Object
Deletes all the records from the collection. For has_many
associations, the deletion is done according to the strategy specified by the :dependent
option. Returns an array with the deleted records.
If no :dependent
option is given, then it will follow the default strategy. The default strategy is :nullify
. This sets the foreign keys to NULL
. For, has_many
:through
, the default strategy is delete_all
.
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>
# ]
If it is set to :destroy
all the objects from the collection 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_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>
# ]
Pet.find(1, 2, 3)
# => ActiveRecord::RecordNotFound
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 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>
# ]
Pet.find(1, 2, 3)
# => ActiveRecord::RecordNotFound
421 422 423 |
# File 'lib/active_record/associations/collection_proxy.rb', line 421 def delete_all @association.delete_all end |
#destroy(*records) ⇒ Object
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 IDs (1, 2, 3)
You can pass Fixnum
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 IDs (4, 5, 6)
637 638 639 |
# File 'lib/active_record/associations/collection_proxy.rb', line 637 def destroy(*records) @association.destroy(*records) end |
#destroy_all ⇒ Object
Deletes the records of the collection directly from the database. This will always remove the records ignoring the :dependent
option.
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
447 448 449 |
# File 'lib/active_record/associations/collection_proxy.rb', line 447 def destroy_all @association.destroy_all end |
#distinct ⇒ Object Also known as: uniq
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">]
655 656 657 |
# File 'lib/active_record/associations/collection_proxy.rb', line 655 def distinct @association.distinct end |
#empty? ⇒ Boolean
Returns true
if the collection is empty. If the collection has been loaded or the :counter_sql
option is provided, 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.length.zero?
.
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
747 748 749 |
# File 'lib/active_record/associations/collection_proxy.rb', line 747 def empty? @association.empty? end |
#find(*args, &block) ⇒ Object
Finds an object in the collection responding to the id
. Uses the same rules as ActiveRecord::Base.find
. Returns ActiveRecord::RecordNotFound
error if the object can not 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>
# ]
140 141 142 |
# File 'lib/active_record/associations/collection_proxy.rb', line 140 def find(*args, &block) @association.find(*args, &block) end |
#first(*args) ⇒ Object
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) # => []
170 171 172 |
# File 'lib/active_record/associations/collection_proxy.rb', line 170 def first(*args) @association.first(*args) end |
#include?(record) ⇒ Boolean
Returns true
if the given object 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
832 833 834 |
# File 'lib/active_record/associations/collection_proxy.rb', line 832 def include?(record) !!@association.include?(record) end |
#last(*args) ⇒ Object
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) # => []
200 201 202 |
# File 'lib/active_record/associations/collection_proxy.rb', line 200 def last(*args) @association.last(*args) end |
#length ⇒ Object
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>
# ]
725 726 727 |
# File 'lib/active_record/associations/collection_proxy.rb', line 725 def length @association.length end |
#load_target ⇒ Object
44 45 46 |
# File 'lib/active_record/associations/collection_proxy.rb', line 44 def load_target @association.load_target end |
#loaded? ⇒ Boolean
Returns true
if the association has been loaded, otherwise false
.
person.pets.loaded? # => false
person.pets
person.pets.loaded? # => true
53 54 55 |
# File 'lib/active_record/associations/collection_proxy.rb', line 53 def loaded? @association.loaded? end |
#many?(&block) ⇒ Boolean
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
818 819 820 |
# File 'lib/active_record/associations/collection_proxy.rb', line 818 def many?(&block) @association.many?(&block) end |
#prepend(*args) ⇒ Object
948 949 950 |
# File 'lib/active_record/associations/collection_proxy.rb', line 948 def prepend(*args) raise NoMethodError, "prepend on association is not defined. Please use << or append" end |
#proxy_association ⇒ Object
836 837 838 |
# File 'lib/active_record/associations/collection_proxy.rb', line 836 def proxy_association @association end |
#reload ⇒ Object
Reloads the collection from the database. Returns self
. Equivalent to collection(true)
.
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>]
person.pets(true) # fetches pets from the database
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
978 979 980 981 |
# File 'lib/active_record/associations/collection_proxy.rb', line 978 def reload proxy_association.reload self end |
#replace(other_array) ⇒ Object
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
329 330 331 |
# File 'lib/active_record/associations/collection_proxy.rb', line 329 def replace(other_array) @association.replace(other_array) end |
#scope ⇒ Object Also known as: spawn
Returns a Relation
object for the records in this association
849 850 851 |
# File 'lib/active_record/associations/collection_proxy.rb', line 849 def scope @association.scope end |
#scoping ⇒ Object
We don’t want this object to be put on the scoping stack, because that could create an infinite loop where we call an @association method, which gets the current scope, which is this object, which delegates to @association, and so on.
844 845 846 |
# File 'lib/active_record/associations/collection_proxy.rb', line 844 def scoping @association.scope.scoping { yield } end |
#select(select = nil, &block) ⇒ Object
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 that is not in the initialized record you’ll receive:
person.pets.select(:name).first.person_id
# => ActiveModel::MissingAttributeError: missing attribute: person_id
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| pet.name =~ /oo/ }
# => [
# #<Pet id: 2, name: "Spook", person_id: 1>,
# #<Pet id: 3, name: "Choo-Choo", person_id: 1>
# ]
person.pets.select(:name) { |pet| pet.name =~ /oo/ }
# => [
# #<Pet id: 2, name: "Spook">,
# #<Pet id: 3, name: "Choo-Choo">
# ]
110 111 112 |
# File 'lib/active_record/associations/collection_proxy.rb', line 110 def select(select = nil, &block) @association.select(select, &block) end |
#size ⇒ Object
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.
701 702 703 |
# File 'lib/active_record/associations/collection_proxy.rb', line 701 def size @association.size end |
#target ⇒ Object
40 41 42 |
# File 'lib/active_record/associations/collection_proxy.rb', line 40 def target @association.target end |
#to_ary ⇒ Object Also known as: to_a
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>
# ]
917 918 919 |
# File 'lib/active_record/associations/collection_proxy.rb', line 917 def to_ary load_target.dup end |