Spec-Zone.ru › Ruby on Rails 4.2

класс ActiveRecord::Relation

Родитель:
Объект
Включенные модули:
ActiveRecord::FinderMethods, ActiveRecord::Calculations, ActiveRecord::SpawnMethods, ActiveRecord::QueryMethods, ActiveRecord::Batches, ActiveRecord::Explain, ActiveRecord::Delegation

Active Record Связь

Константы

INVALID_METHODS_FOR_DELETE_ALL
MULTI_VALUE_METHODS
SINGLE_VALUE_METHODS
VALUE_METHODS

Атрибуты

klass[R]
loaded[R]
loaded?[R]
model[R]
table[R]

Общедоступные методы класса

new(klass, table, values = {}) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 22
def initialize(klass, table, values = {})
  @klass  = klass
  @table  = table
  @values = values
  @offsets = {}
  @loaded = false
end

Общедоступные методы экземпляров

==(other) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 604
def ==(other)
  case other
  when Associations::CollectionProxy, AssociationRelation
    self == other.to_a
  when Relation
    other.to_sql == to_sql
  when Array
    to_a == other
  end
end

Сравнивает два отношения на предмет равенства.

any?() { |*block_args| ... } Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 273
def any?
  if block_given?
    to_a.any? { |*block_args| yield(*block_args) }
  else
    !empty?
  end
end

Возвращает true, если существуют какие-либо записи.

blank?() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 620
def blank?
  to_a.blank?
end

Возвращает true, если отношение пустое.

build(*args, &block)
Псевдоним для: new
create(*args, &block) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 141
def create(*args, &block)
  scoping { @klass.create(*args, &block) }
end

Попытка создать новую запись с теми же атрибутами, что и в отношении. Возвращает инициализированный объект, если проверка данных завершилась неудачей.

Ожидаются аргументы в том же формате, что и Base.create.

Примеры

users = User.where(name: 'Oscar')
users.create # #<User id: 3, name: "oscar", ...>

users.create(name: 'fxn')
users.create # #<User id: 4, name: "fxn", ...>

users.create { |user| user.name = 'tenderlove' }
# #<User id: 5, name: "tenderlove", ...>

users.create(name: nil) # validation on name
# #<User id: nil, name: nil, ...>
create!(*args, &block) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 149
def create!(*args, &block)
  scoping { @klass.create!(*args, &block) }
end

Аналогично create, но вызывает create! в базовом классе. Выбрасывает исключение, если произошла ошибка проверки данных.

Ожидаются аргументы в том же формате, что и Base.create!.

delete(id_or_array) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 503
def delete(id_or_array)
  where(primary_key => id_or_array).delete_all
end

Удаляет строку с первичным ключом, соответствующим аргументу id, используя SQL-запрос DELETE, и возвращает количество удалённых строк. Объекты Active Record не создаются, поэтому обратные вызовы объекта не выполняются, в том числе любые параметры ассоциации :dependent.

Вы можете удалить несколько строк одновременно, передав массив id.

Примечание: Хотя это часто намного быстрее, чем альтернатива, пропуск обратных вызовов может обойти бизнес-логику в вашем приложении, которая гарантирует целостность ссылок или выполняет другие важные задачи.

Примеры

# Delete a single row
Todo.delete(1)

# Delete multiple rows
Todo.delete([2,3,4])
delete_all(conditions = nil) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 452
def delete_all(conditions = nil)
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
    if MULTI_VALUE_METHODS.include?(method)
      send("#{method}_values").any?
    else
      send("#{method}_value")
    end
  }
  if invalid_methods.any?
    raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
  end

  if conditions
    where(conditions).delete_all
  else
    stmt = Arel::DeleteManager.new(arel.engine)
    stmt.from(table)

    if joins_values.any?
      @klass.connection.join_to_delete(stmt, arel, table[primary_key])
    else
      stmt.wheres = arel.constraints
    end

    bvs = arel.bind_values + bind_values
    affected = @klass.connection.delete(stmt, 'SQL', bvs)

    reset
    affected
  end
end

Удаляет записи, соответствующие conditions, без предварительного создания записей, а значит не вызывая метод destroy и не вызывая обратные вызовы. Это один SQL-запрос DELETE, который идет прямо в базу данных, намного эффективнее, чем destroy_all. Будьте осторожны с отношениями, в частности правила :dependent определенные на ассоциациях не соблюдаются. Возвращает количество затронутых строк.

Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all

Оба вызова удаляют затронутые сообщения сразу одним запросом DELETE. Если вам нужно уничтожить зависимые ассоциации или вызвать свои before_* или after_destroy обратные вызовы, используйте метод destroy_all вместо этого.

Если предоставлен неверный метод, delete_all генерирует ошибку ActiveRecord:

Post.limit(100).delete_all
# => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
find_or_initialize_by(attributes, &block) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 222
def find_or_initialize_by(attributes, &block)
  find_by(attributes) || new(attributes, &block)
end

Как find_or_create_by, но вызывает new вместо create.

initialize_copy(other) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 30
def initialize_copy(other)
  # This method is a hot spot, so for now, use Hash[] to dup the hash.
  #   https://bugs.ruby-lang.org/issues/7166
  @values        = Hash[@values]
  @values[:bind] = @values[:bind].dup if @values.key? :bind
  reset
end
inspect() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 628
def inspect
  entries = to_a.take([limit_value, 11].compact.min).map!(&:inspect)
  entries[10] = '...' if entries.size == 11

  "#<#{self.class.name} [#{entries.join(', ')}]>"
end
joined_includes_values() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 593
def joined_includes_values
  includes_values & joins_values
end

Соединения, которые также помечены для предварительной загрузки. В этом случае мы должны просто загрузить их жадно. Обратите внимание, что это наивное реализация, так как у нас могут быть строки и символы, которые представляют одну и ту же ассоциацию, но которые не совпадают с этим. Кроме того, у нас могут быть вложенные хэши, которые частично совпадают, например { a: :b } и { a: [:b, :c] }

load() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 513
def load
  exec_queries unless loaded?

  self
end

Загружает записи из базы данных, если они еще не загружены. Вы можете использовать это, если по какой-то причине вам нужно явно загрузить некоторые записи, прежде чем фактически использовать их. Возвращаемое значение — сам объект отношения, а не записи.

Post.where(published: true).load # => #<ActiveRecord::Relation>
many?() { |*block_args| ... } Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 282
def many?
  if block_given?
    to_a.many? { |*block_args| yield(*block_args) }
  else
    limit_value ? to_a.many? : size > 1
  end
end

Возвращает true, если записей более одной.

new(*args, &block) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 118
def new(*args, &block)
  scoping { @klass.new(*args, &block) }
end

Инициализирует новую запись из отношения, сохраняя текущий контекст.

Ожидает аргументы в том же формате, что и Base.new.

users = User.where(name: 'DHH')
user = users.new # => #<User id: nil, name: "DHH", created_at: nil, updated_at: nil>

Вы также можете передать блок в new, в котором будет новая запись в качестве аргумента:

user = users.new { |user| user.name = 'Oscar' }
user.name # => Oscar
Также алиасирован как: build
pretty_print(q) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 615
def pretty_print(q)
  q.pp(self.to_a)
end
reload() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 520
def reload
  reset
  load
end

Вынуждает перезагрузку отношения.

reset() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 525
def reset
  @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
  @should_eager_load = @join_dependency = nil
  @records = []
  @offsets = {}
  self
end
scope_for_create() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 578
def scope_for_create
  @scope_for_create ||= where_values_hash.merge(create_with_value)
end
scoping() { || ... } Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 299
def scoping
  previous, klass.current_scope = klass.current_scope, self
  yield
ensure
  klass.current_scope = previous
end

Ограничить все запросы текущим контекстом.

Comment.where(post_id: 1).scoping do
  Comment.first
end
# => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1

Пожалуйста, проверьте unscoped, если вы хотите удалить все предыдущие контексты (включая default_scope) во время выполнения блока.

size() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 256
def size
  loaded? ? @records.length : count(:all)
end

Возвращает размер записей.

to_a() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 241
def to_a
  load
  @records
end

Преобразует объекты отношения в Массив.

to_sql() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 537
def to_sql
  @to_sql ||= begin
                relation   = self
                connection = klass.connection
                visitor    = connection.visitor

                if eager_loading?
                  find_with_associations { |rel| relation = rel }
                end

                arel  = relation.arel
                binds = (arel.bind_values + relation.bind_values).dup
                binds.map! { |bv| connection.quote(*bv.reverse) }
                collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
                collect.substitute_binds(binds).join
              end
end

Возвращает SQL-запрос для отношения.

User.where(name: 'Oscar').to_sql
# => SELECT "users".* FROM "users"  WHERE "users"."name" = 'Oscar'
uniq_value() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 599
def uniq_value
  distinct_value
end

uniq и uniq! устарели. uniq_value делегирует distinct_value, чтобы сохранить обратную совместимость. Используйте distinct_value вместо этого.

update(id, attributes) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 363
def update(id, attributes)
  if id.is_a?(Array)
    id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
  else
    object = find(id)
    object.update(attributes)
    object
  end
end

Обновляет объект (или несколько объектов) и сохраняет его в базе данных, если валидация пройдена. Результирующий объект возвращается, независимо от того, был ли объект успешно сохранен в базе данных или нет.

Параметры

  • id - Это должен быть ID или массив ID для обновления.

  • attributes - Это должен быть хэш атрибутов или массив хэшей.

Примеры

# Updates one record
Person.update(15, user_name: 'Samuel', group: 'expert')

# Updates multiple records
people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
Person.update(people.keys, people.values)
update_all(updates) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 326
def update_all(updates)
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?

  stmt = Arel::UpdateManager.new(arel.engine)

  stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
  stmt.table(table)
  stmt.key = table[primary_key]

  if joins_values.any?
    @klass.connection.join_to_update(stmt, arel)
  else
    stmt.take(arel.limit)
    stmt.order(*arel.orders)
    stmt.wheres = arel.constraints
  end

  bvs = arel.bind_values + bind_values
  @klass.connection.update stmt, 'SQL', bvs
end

Обновляет все записи в текущем отношении с указанными данными. Этот метод строит одно SQL-выражение UPDATE и отправляет его напрямую в базу данных. Он не создает связанные модели и не запускает Active Record обратные вызовы или валидацию. Значения, передаваемые в `update_all`, не будут проходить типизацию Active Record. Оно должно принимать только значения, которые могут быть переданы непосредственно в SQL-базу данных.

Параметры

  • updates - Строка, массив или хэш, представляющий часть SET SQL-запроса.

Примеры

# Update all customers with the given attributes
Customer.update_all wants_email: true

# Update all books with 'Rails' in their title
Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')

# Update all books that match conditions, but limit it to 5 ordered by date
Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
values() Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 624
def values
  Hash[@values]
end
where_values_hash(relation_table_name = table_name) Показать исходный код
# File activerecord/lib/active_record/relation.rb, line 559
def where_values_hash(relation_table_name = table_name)
  equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node|
    node.left.relation.name == relation_table_name
  }

  binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]

  Hash[equalities.map { |where|
    name = where.left.name
    [name, binds.fetch(name.to_s) {
      case where.right
      when Array then where.right.map(&:val)
      when Arel::Nodes::Casted
        where.right.val
      end
    }]
  }]
end

Возвращает хэш условий where.

User.where(name: 'Oscar').where_values_hash
# => {name: "Oscar"}

© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API