class ActiveFedora::Associations::CollectionProxy
:nodoc:
instantiation of the actual post records.
is computed directly through Solr and does not trigger by itself the
blog.posts.count
The @target
object is not loaded until needed. For example,
ActiveFedora::Associations::HasManyAssociation.
though the object behind blog.posts
is not an Array, but an
blog.posts.class # => Array
corner case, it even removes the class
method and that’s why you get
unknown methods to @target
via method_missing
. As a
This class has most of the basic instance methods removed, and delegates
the @reflection
object represents a :has_many
macro.@owner
, the collection of its posts as @target
, and
the association proxy in blog.posts
has the object in blog
as
blog = Blog.find(:first)
end
has_many :posts
class Blog < ActiveFedora::Base
For example, given
ActiveFedora::Reflection::AssociationReflection.
about is available in @reflection
. That’s an instance of the class
object, known as the @target
. The kind of association any proxy is
holds the association, known as the @owner
, and the actual associated
Association proxies in Active Fedora are middlemen between the object that
def <<(*records)
def <<(*records) proxy_association.concat(records) && self end
def any?(&block)
end
pet.group == 'dogs'
person.pets.any? do |pet|
# => false
end
pet.group == 'cats'
person.pets.any? do |pet|
# => [#
person.pets
criteria is not empty.
is the same, it returns true if the collection based on the
You can also pass a block to define criteria. The behavior
person.pets.any? # => true
person.pets.count # => 0
person.pets << Pet.new(name: 'Snoop')
person.pets.any? # => false
person.pets.count # => 0
end
has_many :pets
class Person < ActiveFedora::Base
Returns +true+ if the collection is not empty.
def any?(&block) @association.any?(&block) end
def build(attributes = {}, &block)
person.pets.size # => 5 # size of the collection
# ]
# #
# #
# #
# => [
person.pets.build([{name: 'Spook'}, {name: 'Choo-Choo'}, {name: 'Brain'}])
# => #
person.pets.build(name: 'Fancy-Fancy')
# => #
person.pets.build
end
has_many :pets
class Person
with the new objects.
You can pass an array of attributes hashes, this will return an array
with +attributes+ and linked to this object, but have not yet been saved.
Returns a new object of the collection type that has been instantiated
def build(attributes = {}, &block) @association.build(attributes, &block) end
def clear
def clear delete_all self end
def concat(*records)
person.pets.concat([Pet.new(name: 'Brain'), Pet.new(name: 'Benny')])
# ]
# #
# #
# #
# => [
person.pets
person.id # => 1
person.pets.size # => 3
person.pets.concat(Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo'))
person.pets.concat(Pet.new(name: 'Fancy-Fancy'))
person.pets.size # => 0
end
pets :has_many
class Person < ActiveFedora::Base
so method calls may be chained.
inserts each record, +push+ and +concat+ behave identically. Returns +self+
to the association's primary key. Since << flattens its argument list and
Add one or more records to the collection by setting their foreign keys
def concat(*records) @association.concat(*records) end
def count(options = {})
# #
# #
# #
# => [
person.pets
person.pets.count # => 3
end
has_many :pets
class Person < ActiveFedora::Base
Count all records using Solr.
def count(options = {}) @association.count(options) end
def create(attributes = {}, &block)
# #
# #
# #
# => [
person.pets.find(1, 2, 3)
person.pets.count # => 3
person.pets.size # => 3
# ]
# #
# #
# => [
person.pets.create([{name: 'Spook'}, {name: 'Choo-Choo'}])
# => #
person.pets.create(name: 'Fancy-Fancy')
end
has_many :pets
class Person
passes the validations).
attributes, linked to this object and that has already been saved (if it
Returns a new object of the collection type that has been instantiated with
def create(attributes = {}, &block) @association.create(attributes, &block) end
def create!(attributes = {}, &block)
person.pets.create!(name: nil)
end
validates :name, presence: true
class Pet
end
has_many :pets
class Person
Like +create+, except that if the record is invalid, raises an exception.
def create!(attributes = {}, &block) @association.create!(attributes, &block) end
def delete(*records)
# #
# #
# => [
person.pets.delete(2, 3)
# => [#
person.pets.delete("1")
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets
class Person < ActiveFedora::Base
responding to the +id+ and executes delete on them.
You can pass +Fixnum+ or +String+ values, it finds the records
# => ActiveFedora::RecordNotFound: Couldn't find Pet with id=1
Pet.find(1)
# ]
# #
# #
# => [
person.pets
person.pets.size # => 2
# => [#
person.pets.delete(Pet.find(1))
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets, dependent: :delete_all
class Person < ActiveFedora::Base
*without* calling their +destroy+ method.
If it is set to :delete_all, all the +records+ are deleted
# => ActiveFedora::RecordNotFound: Couldn't find all Pets with IDs (1, 3)
Pet.find(1, 3)
# => [#
person.pets
person.pets.size # => 1
# ]
# #
# #
# => [
person.pets.delete(Pet.find(1), Pet.find(3))
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets, dependent: :destroy
class Person < ActiveFedora::Base
their +destroy+ method. See +destroy+ for more information.
If it is set to :destroy all the +records+ are removed by calling
# => #
Pet.find(1)
# ]
# #
# #
# => [
person.pets
person.pets.size # => 2
# => [#
person.pets.delete(Pet.find(1))
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets # dependent: :nullify option by default
class Person < ActiveFedora::Base
strategy is +delete_all+.
keys to NULL. For, +has_many+ :through, the default
strategy. The default strategy is :nullify. This sets the foreign
If no :dependent option is given, then it will follow the default
deleted records.
specified by the :dependent option. Returns an array with the
+has_many+ associations, the deletion is done according to the strategy
Deletes the +records+ supplied and removes them from the collection. For
def delete(*records) @association.delete(*records) end
def delete_all
Pet.find(1, 2, 3)
# ]
# #
# #
# #
# => [
person.pets.delete_all
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets, dependent: :delete_all
class Person < ActiveFedora::Base
*without* calling their +destroy+ method.
If it is set to :delete_all, all the objects are deleted
# => ActiveFedora::RecordNotFound
Pet.find(1, 2, 3)
# ]
# #
# #
# #
# => [
person.pets.delete_all
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets, dependent: :destroy
class Person < ActiveFedora::Base
information.
are removed by calling their +destroy+ method. See +destroy+ for more
If it is set to :destroy all the objects from the collection
# ]
# #
# #
# #
# => [
Pet.find(1, 2, 3)
person.pets # => []
person.pets.size # => 0
# ]
# #
# #
# #
# => [
person.pets.delete_all
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets # dependent: :nullify option by default
class Person < ActiveFedora::Base
the default strategy is +delete_all+.
sets the foreign keys to NULL. For, +has_many+ :through,
default strategy. The default strategy is :nullify. This
If no :dependent option is given, then it will follow the
option. Returns an array with the deleted records.
the deletion is done according to the strategy specified by the :dependent
Deletes all the records from the collection. For +has_many+ associations,
def delete_all @association.delete_all end
def destroy(*records)
person.pets # => []
person.pets.size # => 0
# ]
# #
# #
# => [
person.pets.destroy(5, 6)
# ]
# #
# #
# => [
person.pets
person.pets.size # => 2
# => #
person.pets.destroy("4")
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
responding to the +id+ and then deletes them from the database.
You can pass +Fixnum+ or +String+ values, it finds the records
Pet.find(1, 2, 3) # => ActiveFedora::RecordNotFound: Couldn't find all Pets with IDs (1, 2, 3)
person.pets # => []
person.pets.size # => 0
# ]
# #
# #
# => [
person.pets.destroy(Pet.find(2), Pet.find(3))
# ]
# #
# #
# => [
person.pets
person.pets.size # => 2
# => [#
person.pets.destroy(Pet.find(1))
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets
class Person < ActiveFedora::Base
the +:dependent+ option. Returns an array with the removed records.
This method will _always_ remove record from the database ignoring
Destroys the +records+ supplied and removes them from the collection.
def destroy(*records) @association.destroy(*records) end
def destroy_all
person.pets # => []
person.pets.size # => 0
person.pets.destroy_all
# ]
# #
# #
# #
# => [
person.pets
person.pets.size # => 3
end
has_many :pets
class Person < ActiveFedora::Base
option.
This will _always_ remove the records ignoring the +:dependent+
Deletes the records of the collection directly from the database.
def destroy_all @association.destroy_all end
def empty?
person.pets.count # => 0
person.pets.delete_all
person.pets.empty? # => false
person.pets.count # => 1
end
has_many :pets
class Person < ActiveFedora::Base
is better to check collection.length.zero?.
not already been loaded and you are going to fetch the records anyway it
it is equivalent to collection.exists?. If the collection has
to collection.size.zero?. If the collection has not been loaded,
loaded or the :counter_sql option is provided, it is equivalent
Returns +true+ if the collection is empty. If the collection has been
def empty? @association.empty? end
def find(*args, &block)
# #
# #
# => [
person.pets.find(2, 3)
# => #
person.pets.find(2) { |pet| pet.name.downcase! }
person.pets.find(4) # => ActiveFedora::RecordNotFound: Couldn't find Pet with id=4
person.pets.find(1) # => #
# ]
# #
# #
# #
# => [
person.pets
end
has_many :pets
class Person < ActiveFedora::Base
error if the object can not be found.
rules as ActiveFedora::Base.find. Returns ActiveFedora::RecordNotFound
Finds an object in the collection responding to the +id+. Uses the same
def find(*args, &block) @association.find(*args, &block) end
def first(*args)
another_person_without.pets.first # => nil
another_person_without.pets # => []
# ]
# #
# #
# => [
person.pets.first(2)
person.pets.first # => #
# ]
# #
# #
# #
# => [
person.pets
end
has_many :pets
class Person < ActiveFedora::Base
form returns an empty array.
If the collection is empty, the first form returns +nil+, and the second
Returns the first record, or the first +n+ records, from the collection.
def first(*args) @association.first(*args) end
def include?(record)
person.pets.include?(Pet.find(20)) # => true
person.pets # => [#
end
has_many :pets
class Person < ActiveFedora::Base
Returns +true+ if the given object is present in the collection.
def include?(record) @association.include?(record) end
def initialize(association)
def initialize(association) @association = association super association.klass merge! association.scope end
def last(*args)
another_person_without.pets.last # => nil
another_person_without.pets # => []
# ]
# #
# #
# => [
person.pets.last(2)
person.pets.last # => #
# ]
# #
# #
# #
# => [
person.pets
end
has_many :pets
class Person < ActiveFedora::Base
form returns an empty array.
If the collection is empty, the first form returns +nil+, and the second
Returns the last record, or the last +n+ records, from the collection.
def last(*args) @association.last(*args) end
def length
# #
# #
# #
# => [
person.pets
# call the collection with no additional queries:
# Because the collection is loaded, you can
# queries solr for the number of matching records where "person_id_ssi" = 1
person.pets.length # => 3
end
has_many :pets
class Person < ActiveFedora::Base
method will take one less query. Otherwise +size+ is more efficient.
equivalent. If not and you are going to need the records anyway this
If the collection has been already loaded, +length+ and +size+ are
Returns the size of the collection calling +size+ on the target.
def length @association.length end
def load_from_solr(opts = Hash.new)
def load_from_solr(opts = Hash.new) @association.load_from_solr(opts) end
def load_target
def load_target @association.load_target end
def loaded?
def loaded? @association.loaded? end
def many?(&block)
end
pet.group == 'cats'
person.pets.many? do |pet|
# => false
end
pet.group == 'dogs'
person.pets.many? do |pet|
# ]
# #
# #
# #
# => [
person.pets
based on the criteria has more than one record.
behavior is the same, it returns true if the collection
You can also pass a block to define criteria. The
person.pets.many? #=> true
person.pets.count #=> 2
person.pets << Pet.new(name: 'Snoopy')
person.pets.many? #=> false
person.pets.count #=> 1
end
has_many :pets
class Person < ActiveFedora::Base
Equivalent to collection.size > 1.
Returns true if the collection has more than one record.
def many?(&block) @association.many?(&block) end
def proxy_association
def proxy_association @association end
def reload
def reload proxy_association.reload self end
def replace(other_array)
person.pets.replace(["doo", "ggie", "gaga"])
an ActiveFedora::AssociationTypeMismatch error:
If the supplied array has an incorrect association type, it raises
# => [#
person.pets
person.pets.replace(other_pets)
other_pets = [Pet.new(name: 'Puff', group: 'celebrities']
# => [#
person.pets
end
has_many :pets
class Person < ActiveFedora::Base
and delete/add only records that have changed.
Replace this collection with +other_array+. This will perform a diff
def replace(other_array) @association.replace(other_array) end
def select(select = nil, &block)
# #
# #
# => [
person.pets.select(:name) { |pet| pet.name =~ /oo/ }
# ]
# #
# #
# => [
person.pets.select { |pet| pet.name =~ /oo/ }
Array#select.
converting them into an array and iterating through them using
This build an array of objects from the database for the scope,
*Second:* You can pass a block so it can be used just like Array#select.
# => ActiveModel::MissingAttributeError: missing attribute: person_id
person.pets.select(:name).first.person_id
receive:
to access a field that is not in the initialized record you’ll
object with only the fields that you’ve selected. If you attempt
Be careful because this also means you’re initializing a model
# ]
# #
# #
# #
# => [
person.pets.select([:id, :name])
# ]
# #
# #
# #
# => [
person.pets.select(:name)
# ]
# #
# #
# #
# => [
person.pets
end
has_many :pets
class Person < ActiveFedora::Base
*First:* Specify a subset of fields to be selected from the result set.
Works in two ways.
def select(select = nil, &block) @association.select(select, &block) end
def size
# Because the collection is already loaded, this will behave like
person.pets.size # => 3
# ]
# #
# #
# #
# => [
person.pets # This will execute a solr query
# queries solr for the number of matching records where "person_id_ssi" = 1
person.pets.size # => 3
end
has_many :pets
class Person < ActiveFedora::Base
+length+ will take one less query. Otherwise +size+ is more efficient.
equivalent. If not and you are going to need the records anyway
If the collection has been already loaded +size+ and +length+ are
collection.size.
it executes a solr query to find the matching records. Else it calls
Returns the size of the collection. If the collection hasn't been loaded,
def size @association.size end
def target
def target @association.target end
def to_ary
def to_ary load_target.dup end
def uniq
person.pets.select(:name).uniq
# ]
# #
# #
# => [
person.pets.select(:name)
end
has_many :pets
class Person < ActiveFedora::Base
Specifies whether the records should be unique or not.
def uniq @association.uniq end