класс ActiveRecord::Associations::CollectionProxy
Провайдеры ассоциаций в Active Record являются посредниками между объектом, который содержит ассоциацию, известным как @owner, и фактическим связанным объектом, известным как @target. Тип ассоциации, о которой идет речь в любом провайдере, доступен в @reflection. Это экземпляр класса ActiveRecord::Reflection::AssociationReflection.
Например, если
class Blog < ActiveRecord::Base has_many :posts end blog = Blog.first
провайдер ассоциации в blog.posts содержит объект в blog в качестве @owner, коллекцию его постов в качестве @target, и объект @reflection представляет макрос :has_many.
Этот класс делегирует неизвестные методы объекту @target через method_missing.
Объект @target загружается только при необходимости. Например,
blog.posts.count
вычисляется напрямую через SQL и сам по себе не вызывает создание фактических записей о постах.
Публичные методы экземпляра
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 1000 def <<(*records) proxy_association.concat(records) && self end
Добавляет одну или несколько records в коллекцию, устанавливая их внешние ключи в первичный ключ ассоциации. Возвращает self, поэтому несколько добавлений могут быть объединены вместе.
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 934 def ==(other) load_target == other end
Эквивалентно Array#==. Возвращает true, если два массива содержат одинаковое количество элементов и если каждый элемент равен соответствующему элементу в массиве other, иначе возвращает 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
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 845 def any?(&block) @association.any?(&block) end
Возвращает true, если коллекция не пуста.
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
Вы также можете передать block для определения критериев. Поведение такое же, возвращает true, если коллекция на основе критериев не пуста.
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 292
def build(attributes = {}, &block)
@association.build(attributes, &block)
end Возвращает новый объект типа коллекции, который был создан с помощью attributes и связан с этим объектом, но еще не сохранен. Вы можете передать массив хэшей атрибутов, это вернет массив с новыми объектами.
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 734 def calculate(operation, column_name) null_scope? ? scope.calculate(operation, column_name) : super end
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 1016 def clear delete_all self end
Эквивалентно delete_all. Разница в том, что возвращает self, вместо массива с удаленными объектами, поэтому методы могут быть объединены. См. delete_all для получения дополнительной информации. Обратите внимание, что поскольку delete_all удаляет записи путем прямого выполнения SQL-запроса в базу данных, столбец updated_at объекта не изменяется.
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 367 def concat(*records) @association.concat(*records) end
Добавить одну или несколько записей в коллекцию, установив их внешние ключи в первичный ключ ассоциации. Поскольку << сглаживает свой список аргументов и вставляет каждую запись, push и concat ведут себя идентично. Возвращает self, поэтому вызовы методов могут быть объединены.
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
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 730 def count(column_name = nil) @association.count(column_name) end
Подсчитать все записи с помощью 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> # ]
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 323
def create(attributes = {}, &block)
@association.create(attributes, &block)
end Возвращает новый объект типа коллекции, который был создан с атрибутами, связан с этим объектом и уже сохранен (если он проходит проверки).
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 339
def create!(attributes = {}, &block)
@association.create!(attributes, &block)
end Как create, за исключением того, что если запись недействительна, возникает исключение.
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 622 def delete(*records) @association.delete(*records) end
Удаляет предоставленные records из коллекции в соответствии со стратегией, указанной параметром :dependent. Если параметр :dependent не указан, то будет использоваться стратегия по умолчанию. Возвращает массив с удаленными записями.
Для ассоциаций has_many :through, стратегия удаления по умолчанию — :delete_all.
Для ассоциаций has_many, стратегия удаления по умолчанию — :nullify. Это устанавливает внешние ключи в 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>
Если он установлен в :destroy, все records удаляются путем вызова их метода destroy. См. destroy для получения дополнительной информации.
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)
Если он установлен в :delete_all, все records удаляются без вызова их метода destroy.
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
Вы можете передать значения Integer или String, он находит записи, соответствующие id, и выполняет для них delete.
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 476 def delete_all(dependent = nil) @association.delete_all(dependent) end
Удаляет все записи из коллекции в соответствии со стратегией, указанной параметром :dependent. Если параметр :dependent не указан, то будет использоваться стратегия по умолчанию.
Для ассоциаций has_many :through, стратегия удаления по умолчанию — :delete_all.
Для ассоциаций has_many, стратегия удаления по умолчанию — :nullify. Это устанавливает внешние ключи в 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> # ]
Зависимости has_many и has_many :through по умолчанию используют стратегию :delete_all, если параметр :dependent установлен в :destroy. Записи не создаются, и обратные вызовы не вызываются.
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)
Если он установлен в :delete_all, все объекты удаляются без вызова их метода destroy.
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 694 def destroy(*records) @association.destroy(*records) end
Уничтожает предоставленные records и удаляет их из коллекции. Этот метод всегда будет удалять запись из базы данных, игнорируя параметр :dependent. Возвращает массив с удаленными записями.
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)
Вы можете передать значения Integer или String, он находит записи, соответствующие id, а затем удаляет их из базы данных.
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 503 def destroy_all @association.destroy_all end
Удаляет записи коллекции непосредственно из базы данных, игнорируя параметр :dependent. Записи создаются, и вызываются обратные вызовы before_remove, after_remove , before_destroy и after_destroy.
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 712 def distinct @association.distinct end
Указывает, должны ли записи быть уникальными или нет.
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">]
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 812 def empty? @association.empty? end
Возвращает true если коллекция пуста. Если коллекция загружена, это эквивалентно collection.size.zero?. Если коллекция не загружена, это эквивалентно !collection.exists?. Если коллекция ещё не загружена, и вы собираетесь получить записи в любом случае, лучше проверить 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
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 189 def fifth(*args) @association.fifth(*args) end
То же, что и first, за исключением того, что возвращает только пятую запись.
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 139 def find(*args, &block) @association.find(*args, &block) end
Находит объект в коллекции, соответствующий id. Использует те же правила, что и ActiveRecord::Base.find. Возвращает ошибку ActiveRecord::RecordNotFound, если объект не найден.
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 169 def first(*args) @association.first(*args) end
Возвращает первую запись или первые n записей из коллекции. Если коллекция пуста, первая форма возвращает nil, а вторая форма возвращает пустой массив.
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 195 def forty_two(*args) @association.forty_two(*args) end
То же, что и first, за исключением того, что возвращает только сорок вторую запись. Также известно как доступ к «reddit».
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 184 def fourth(*args) @association.fourth(*args) end
То же, что и first, за исключением того, что возвращает только четвёртую запись.
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 897 def include?(record) !!@association.include?(record) end
Возвращает true, если данная record присутствует в коллекции.
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 235 def last(*args) @association.last(*args) end
Возвращает последнюю запись или последние n записей из коллекции. Если коллекция пуста, первая форма возвращает nil, а вторая форма возвращает пустой массив.
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 790 def length @association.length end
Возвращает размер коллекции, вызывая size для целевого объекта. Если коллекция уже загружена, length и size эквивалентны. Если нет, и вам всё равно понадобятся записи, этот метод займёт на один запрос меньше. В противном случае size более эффективен.
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 43 def load_target @association.load_target end
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 52 def loaded? @association.loaded? end
Возвращает true, если ассоциация загружена, в противном случае false.
person.pets.loaded? # => false person.pets person.pets.loaded? # => true
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 883 def many?(&block) @association.many?(&block) end
Возвращает true, если коллекция содержит более одной записи. Эквивалентно 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
Вы также можете передать block, чтобы определить критерии. Поведение такое же: возвращается true, если коллекция, основанная на критериях, содержит более одной записи.
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 738 def pluck(*column_names) null_scope? ? scope.pluck(*column_names) : super end
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 1006 def prepend(*args) raise NoMethodError, "prepend on association is not defined. Please use <<, push or append" end
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 901 def proxy_association @association end
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 1039 def reload proxy_association.reload reset_scope end
Перезагружает коллекцию из базы данных. Возвращает self. Эквивалентно 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>]
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 393 def replace(other_array) @association.replace(other_array) end
Заменяет эту коллекцию на other_array. Это выполнит сравнение и удалит/добавит только записи, которые изменились.
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>]
Если предоставленный массив имеет неверный тип ассоциации, возникает ошибка ActiveRecord::AssociationTypeMismatch:
person.pets.replace(["doo", "ggie", "gaga"]) # => ActiveRecord::AssociationTypeMismatch: Pet expected, got String
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 1060 def reset proxy_association.reset proxy_association.reset_scope reset_scope end
Разгружает ассоциацию. Возвращает 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 906 def scope @scope ||= @association.scope end
Возвращает объект Relation для записей в этой ассоциации
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 174 def second(*args) @association.second(*args) end
То же, что и first, за исключением того, что возвращает только вторую запись.
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 205 def second_to_last(*args) @association.second_to_last(*args) end
То же, что и first, за исключением того, что возвращает только предпоследнюю запись.
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 109 def select(*fields, &block) @association.select(*fields, &block) end
Работает двумя способами.
Во-первых: Укажите подмножество полей для выбора из набора результатов.
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"> # ]
Будьте внимательны, так как это также означает инициализацию объекта модели только с выбранными полями. Если вы попытаетесь получить доступ к полю, id которое не входит в инициализированную запись, вы получите:
person.pets.select(:name).first.person_id # => ActiveModel::MissingAttributeError: missing attribute: person_id
Во-вторых: Вы можете передать блок, чтобы его можно было использовать как Array#select. Это создает массив объектов из базы данных для области действия, преобразуя их в массив и итерируя по нему с помощью 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">
# ]
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 766 def size @association.size end
Возвращает размер коллекции. Если коллекция не загружена, выполняется SELECT COUNT(*) запрос. В противном случае вызывается collection.size.
Если коллекция уже загружена size и length эквивалентны. Если нет, и вам все равно понадобятся записи length выполнится на одну запрос меньше. В противном случае size более эффективен.
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 264 def take(n = nil) @association.take(n) end
Возвращает запись (или N записей, если параметр задан) из коллекции по тем же правилам, что и ActiveRecord::Base.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 39 def target @association.target end
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 179 def third(*args) @association.third(*args) end
Аналогично first, но возвращает только третью запись.
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 200 def third_to_last(*args) @association.third_to_last(*args) end
Аналогично first, но возвращает только третью с конца запись.
# File activerecord/lib/active_record/associations/collection_proxy.rb, line 971 def to_ary load_target.dup end
Возвращает новый массив объектов из коллекции. Если коллекция не загружена, извлекает записи из базы данных.
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> # ]
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.