класс ActiveRecord::Relation
Отображение Active Record
Константы
- CLAUSE_METHODS
- INVALID_METHODS_FOR_DELETE_ALL
- MULTI_VALUE_METHODS
- SINGLE_VALUE_METHODS
- VALUE_METHODS
Атрибуты
Публичные методы класса
# File activerecord/lib/active_record/relation.rb, line 28
def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
@klass = klass
@table = table
@values = values
@loaded = false
@predicate_builder = predicate_builder
@delegate_to_klass = false
@future_result = nil
@records = nil
@async = false
@none = false
end Методы публичного экземпляра
# File activerecord/lib/active_record/relation.rb, line 798
def ==(other)
case other
when Associations::CollectionProxy, AssociationRelation
self == other.records
when Relation
other.to_sql == to_sql
when Array
records == other
end
end Сравнивает два отношения на равенство.
# File activerecord/lib/active_record/relation.rb, line 302 def any?(*args) return false if @none return super if args.present? || block_given? !empty? end
Возвращает true, если существуют какие-либо записи.
# File activerecord/lib/active_record/relation.rb, line 819 def blank? records.blank? end
Возвращает true, если отношение пустое.
# File activerecord/lib/active_record/relation.rb, line 344
def cache_key(timestamp_column = "updated_at")
@cache_keys ||= {}
@cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
end Возвращает стабильный ключ кеша, который можно использовать для идентификации этого запроса. Ключ кеша создается с отпечатком пальца SQL-запроса.
Product.where("name like ?", "%Cosmic Encounter%").cache_key
# => "products/query-1850ab3d302391b85b8693e941286659"
Если ActiveRecord::Base.collection_cache_versioning выключен, как это было в Rails 6.0 и ранее, ключ кеша также будет содержать версию.
ActiveRecord::Base.collection_cache_versioning = false
Product.where("name like ?", "%Cosmic Encounter%").cache_key
# => "products/query-1850ab3d302391b85b8693e941286659-1-20150714212553907087000"
Вы также можете передать пользовательский столбец со временем, чтобы получить метку времени последнего обновленного записей.
Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
# File activerecord/lib/active_record/relation.rb, line 423
def cache_key_with_version
if version = cache_version
"#{cache_key}-#{version}"
else
cache_key
end
end Возвращает ключ кеша вместе с версией.
# File activerecord/lib/active_record/relation.rb, line 371
def cache_version(timestamp_column = :updated_at)
if collection_cache_versioning
@cache_versions ||= {}
@cache_versions[timestamp_column] ||= compute_cache_version(timestamp_column)
end
end Возвращает версию кеша, которая может быть использована вместе с ключом кеша для формирования схемы кеширования, которая можно использовать повторно. Версия кеша создается с количеством записей, соответствующих запросу, и отметкой времени последней обновленной записи. При появлении новой записи, соответствующей запросу, или при обновлении или удалении любой из существующих записей, версия кеша изменяется.
Если коллекция загружена, метод будет перебирать записи, чтобы сгенерировать метку времени, в противном случае он вызовет один SQL-запрос, подобный:
SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%') # File activerecord/lib/active_record/relation.rb, line 98
def create(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
else
block = current_scope_restoring_block(&block)
scoping { _create(attributes, &block) }
end
end Попытка создания новой записи с теми же атрибутами, ограниченными в рамках отношения. Возвращает инициализированный объект, если проверка валидности завершается неудачно.
Ожидаются аргументы в том же формате, что и в ActiveRecord::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, ...>
# File activerecord/lib/active_record/relation.rb, line 113
def create!(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create!(attr, &block) }
else
block = current_scope_restoring_block(&block)
scoping { _create!(attributes, &block) }
end
end Аналогично create, но вызывает create! для базового класса. Выбрасывает исключение, если возникает ошибка валидации.
Ожидаются аргументы в том же формате, что и в ActiveRecord::Base.create!.
# File activerecord/lib/active_record/relation.rb, line 215
def create_or_find_by(attributes, &block)
transaction(requires_new: true) { create(attributes, &block) }
rescue ActiveRecord::RecordNotUnique
if connection.transaction_open?
where(attributes).lock.find_by!(attributes)
else
find_by!(attributes)
end
end Попытка создания записи с заданными атрибутами в таблице, имеющей уникальное ограничение базы данных на один или несколько столбцов. Если строка уже существует с одним или несколькими из этих уникальных ограничений, исключение, которое обычно генерирует такая вставка, перехватывается, и существующая запись с этими атрибутами находится с помощью find_by!.
Это аналогично find_or_create_by, но сначала пытается создать запись. Таким образом, это лучше подходит для случаев, когда запись, скорее всего, ещё не существует.
Однако существует несколько недостатков create_or_find_by:
-
Базовая таблица должна иметь соответствующие столбцы, определенные с уникальными ограничениями базы данных.
-
Нарушение уникального ограничения может быть вызвано только одним или менее чем всеми заданными атрибутами. Это означает, что последующий find_by! может не найти соответствующую запись, что приведет к возбуждению исключения
ActiveRecord::RecordNotFound, а не записи с заданными атрибутами. -
Хотя мы избегаем конкурентной ситуации между SELECT -> INSERT из
find_or_create_by, у нас фактически есть другая конкурентная ситуация между INSERT -> SELECT, которая может быть вызвана, если другой клиент выполняет DELETE между этими двумя операторами. Однако для большинства приложений это значительно менее вероятная ситуация. -
Он полагается на обработку исключений для управления потоком управления, что может быть несколько медленнее.
-
Первичный ключ может автоматически увеличиваться при каждом создании, даже если он терпит неудачу. Это может ускорить проблему исчерпания целых чисел, если базовая таблица по-прежнему использует первичный ключ типа int (примечание: все приложения Rails с версии 5.1+ по умолчанию используют bigint, что не подвержено этой проблеме).
Этот метод вернет запись, если все заданные атрибуты покрыты уникальными ограничениями (если не вызвана ситуация гонки INSERT -> DELETE -> SELECT), но если попытка создания была предпринята и завершилась неудачей из-за ошибок валидации, она не будет сохранена; вы получите то, что возвращает create в такой ситуации.
# File activerecord/lib/active_record/relation.rb, line 228
def create_or_find_by!(attributes, &block)
transaction(requires_new: true) { create!(attributes, &block) }
rescue ActiveRecord::RecordNotUnique
if connection.transaction_open?
where(attributes).lock.find_by!(attributes)
else
find_by!(attributes)
end
end Подобно create_or_find_by, но вызывает create!, поэтому при возникновении ошибки валидации созданной записи возбуждается исключение.
# File activerecord/lib/active_record/relation.rb, line 631
def delete_all
return 0 if @none
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
value = @values[method]
method == :distinct ? value : value&.any?
end
if invalid_methods.any?
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
end
arel = eager_loading? ? apply_join_dependency.arel : build_arel
arel.source.left = table
group_values_arel_columns = arel_columns(group_values.uniq)
having_clause_ast = having_clause.ast unless having_clause.empty?
stmt = arel.compile_delete(table[primary_key], having_clause_ast, group_values_arel_columns)
klass.connection.delete(stmt, "#{klass} Delete All").tap { reset }
end Удаляет записи без предварительной инициализации записей и, следовательно, не вызывает метод #destroy ни не вызывает обратные вызовы. Это единственное SQL-утверждение DELETE, которое идет непосредственно в базу данных, намного эффективнее, чем destroy_all. Однако будьте осторожны с отношениями, в частности, правила :dependent, определенные для ассоциаций, не соблюдаются. Возвращает количество затронутых строк.
Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
Оба вызова удаляют затронутые сообщения сразу с помощью одного оператора DELETE. Если вам нужно уничтожить зависимые ассоциации или вызвать свои before_* или after_destroy обратные вызовы, используйте метод destroy_all вместо этого.
Если передается неверный метод, delete_all генерирует ActiveRecordError:
Post.distinct.delete_all # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
# File activerecord/lib/active_record/relation.rb, line 674 def delete_by(*args) where(*args).delete_all end
Находит и удаляет все записи, соответствующие указанным условиям. Это сокращенная запись для relation.where(condition).delete_all. Возвращает количество затронутых строк.
Если запись не найдена, возвращает 0, так как строк, которые были затронуты, ноль.
Person.delete_by(id: 13)
Person.delete_by(name: 'Spartacus', rating: 4)
Person.delete_by("published_at < ?", 2.weeks.ago)
# File activerecord/lib/active_record/relation.rb, line 609
def destroy_all
records.each(&:destroy).tap { reset }
end Уничтожает записи, создавая экземпляр каждой записи и вызывая её метод #destroy. Выполняются обратные вызовы каждого объекта (включая параметры ассоциации :dependent). Возвращает коллекцию уничтоженных объектов; каждый из них будет заморожен, чтобы отразить, что изменения не должны вноситься (так как они не могут быть сохранены).
Примечание: Создание экземпляров, выполнение обратных вызовов и удаление каждой записи может занимать много времени, когда вы удаляете много записей одновременно. Это генерирует как минимум один запрос SQL DELETE на запись (или, возможно, больше, чтобы обеспечить выполнение ваших обратных вызовов). Если вы хотите быстро удалить много строк, не беспокоясь об их ассоциациях или обратных вызовах, используйте delete_all вместо этого.
Примеры
Person.where(age: 0..18).destroy_all
# File activerecord/lib/active_record/relation.rb, line 661 def destroy_by(*args) where(*args).destroy_all end
Находит и уничтожает все записи, соответствующие указанным условиям. Это сокращенная запись для relation.where(condition).destroy_all. Возвращает коллекцию уничтоженных объектов.
Если запись не найдена, возвращает пустой массив.
Person.destroy_by(id: 13)
Person.destroy_by(name: 'Spartacus', rating: 4)
Person.destroy_by("published_at < ?", 2.weeks.ago)
# File activerecord/lib/active_record/relation.rb, line 783
def eager_loading?
@should_eager_load ||=
eager_load_values.any? ||
includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?)
end Возвращает true, если для связи требуется нетерпеливая загрузка.
# File activerecord/lib/active_record/relation.rb, line 283
def empty?
return true if @none
if loaded?
records.empty?
else
!exists?
end
end Возвращает true, если записей нет.
# File activerecord/lib/active_record/relation.rb, line 269 def encode_with(coder) coder.represent_seq(nil, records) end
Сериализует объекты связи Array.
# File activerecord/lib/active_record/relation.rb, line 253
def explain(*options)
exec_explain(collecting_queries_for_explain { exec_queries }, options)
end Выполняет EXPLAIN для запроса или запросов, запущенных этой связью, и возвращает результат в виде строки. Строка отформатирована, имитируя строки, выводимые оболочкой базы данных.
Обратите внимание, что этот метод фактически выполняет запросы, поскольку результаты некоторых из них необходимы для последующих запросов при активной нетерпеливой загрузке.
Дополнительные сведения см. в руководстве Active Record Query Interface.
# File activerecord/lib/active_record/relation.rb, line 175 def find_or_create_by(attributes, &block) find_by(attributes) || create_or_find_by(attributes, &block) end
Находит первую запись с заданными атрибутами или создает запись с этими атрибутами, если запись не найдена:
# Find the first user named "Penélope" or create a new one. User.find_or_create_by(first_name: 'Penélope') # => #<User id: 1, first_name: "Penélope", last_name: nil> # Find the first user named "Penélope" or create a new one. # We already have one so the existing record will be returned. User.find_or_create_by(first_name: 'Penélope') # => #<User id: 1, first_name: "Penélope", last_name: nil> # Find the first user named "Scarlett" or create a new one with # a particular last name. User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett') # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
Этот метод принимает блок, который передается в create. Последний пример выше можно альтернативно записать следующим образом:
# Find the first user named "Scarlett" or create a new one with a # particular last name. User.find_or_create_by(first_name: 'Scarlett') do |user| user.last_name = 'Johansson' end # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
Этот метод всегда возвращает запись, но если создание было предпринято и завершилось неудачей из-за ошибок проверки, оно не будет сохранено, вы получите то, что возвращает create в такой ситуации.
Если создание завершилось неудачей из-за уникального ограничения, этот метод предположит, что он столкнулся с условием гонки и попытается найти запись еще раз. Если каким-то образом второй поиск все еще не найдет запись из-за одновременного удаления DELETE, он затем вызовет исключение ActiveRecord::RecordNotFound.
Обратите внимание, что этот метод не является атомарным, он сначала выполняет SELECT, а если результатов нет, предпринимается попытка INSERT. Таким образом, если таблица не имеет соответствующего уникального ограничения, может случиться так, что вы получите две или более похожих записей.
# File activerecord/lib/active_record/relation.rb, line 182 def find_or_create_by!(attributes, &block) find_by(attributes) || create_or_find_by!(attributes, &block) end
Как find_or_create_by, но вызывает create!, поэтому исключение возникает, если созданная запись недействительна.
# File activerecord/lib/active_record/relation.rb, line 240 def find_or_initialize_by(attributes, &block) find_by(attributes) || new(attributes, &block) end
Как find_or_create_by, но вызывает new вместо create.
# File activerecord/lib/active_record/relation.rb, line 41 def initialize_copy(other) @values = @values.dup reset end
# File activerecord/lib/active_record/relation.rb, line 831
def inspect
subject = loaded? ? records : annotate("loading for inspect")
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
entries[10] = "..." if entries.size == 11
"#<#{self.class.name} [#{entries.join(', ')}]>"
end # File activerecord/lib/active_record/relation.rb, line 793 def joined_includes_values includes_values & joins_values end
Соединения, которые также помечены для предварительной загрузки. В этом случае мы должны просто выполнить их нетерпеливую загрузку. Обратите внимание, что это наивная реализация, поскольку у нас могут быть строки и символы, которые представляют одну и ту же ассоциацию, но которые не совпадают с этим. Кроме того, у нас могут быть вложенные хэши, которые частично совпадают, например, { a: :b } & { a: [:b, :c] }
# File activerecord/lib/active_record/relation.rb, line 725
def load(&block)
if !loaded? || scheduled?
@records = exec_queries(&block)
@loaded = true
end
self
end Заставляет записи загружаться из базы данных, если они еще не загружены. Вы можете использовать это, если по какой-то причине вам нужно явно загрузить некоторые записи перед их фактическим использованием. Возвращаемое значение — сама связь, а не записи.
Post.where(published: true).load # => #<ActiveRecord::Relation>
# File activerecord/lib/active_record/relation.rb, line 696
def load_async
return load if !connection.async_enabled?
unless loaded?
result = exec_main_query(async: connection.current_transaction.closed?)
if result.is_a?(Array)
@records = result
else
@future_result = result
end
@loaded = true
end
self
end Планирует выполнение запроса из пула фоновых потоков.
Post.where(published: true).load_async # => #<ActiveRecord::Relation>
Когда происходит итерация Relation, если фоновый запрос еще не выполнен, он будет выполнен потоком переднего плана.
Обратите внимание, что config.active_record.async_query_executor должен быть настроен для того, чтобы запросы фактически выполнялись одновременно. В противном случае по умолчанию они выполняются в фоновом режиме.
load_async также вернется к выполнению в фоновом режиме в тестовой среде, когда включены транзакционные заглушки.
Если запрос действительно был выполнен в фоновом режиме, журналы Active Record отобразят это, добавив префикс к строке журнала с помощью ASYNC:
ASYNC Post Load (0.0ms) (db time 2ms) SELECT "posts".* FROM "posts" LIMIT 100
# File activerecord/lib/active_record/relation.rb, line 319 def many? return false if @none return super if block_given? return records.many? if loaded? limited_count > 1 end
Возвращает true, если записей больше одной.
Enumerable#many? # File activerecord/lib/active_record/relation.rb, line 69
def new(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| new(attr, &block) }
else
block = current_scope_restoring_block(&block)
scoping { _new(attributes, &block) }
end
end Инициализирует новую запись из отношения, сохраняя текущий контекст.
Ожидает аргументы в том же формате, что и ActiveRecord::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
# File activerecord/lib/active_record/relation.rb, line 294 def none?(*args) return true if @none return super if args.present? || block_given? empty? end
Возвращает true, если записей нет.
# File activerecord/lib/active_record/relation.rb, line 310 def one?(*args) return false if @none return super if args.present? || block_given? return records.one? if loaded? limited_count == 1 end
Возвращает true, если ровно одна запись.
# File activerecord/lib/active_record/relation.rb, line 809
def pretty_print(pp)
subject = loaded? ? records : annotate("loading for pp")
entries = subject.take([limit_value, 11].compact.min)
entries[10] = "..." if entries.size == 11
pp.pp(entries)
end # File activerecord/lib/active_record/relation.rb, line 735 def reload reset load end
Принудительно перезагружает отношение.
# File activerecord/lib/active_record/relation.rb, line 740 def reset @future_result&.cancel @future_result = nil @delegate_to_klass = false @to_sql = @arel = @loaded = @should_eager_load = nil @offsets = @take = nil @cache_keys = nil @cache_versions = nil @records = nil self end
# File activerecord/lib/active_record/relation.rb, line 715 def scheduled? !!@future_result end
Возвращает true , если отношение было запланировано в пуле потоков фонового выполнения.
# File activerecord/lib/active_record/relation.rb, line 776
def scope_for_create
hash = where_clause.to_h(klass.table_name, equality_only: true)
create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
hash
end # File activerecord/lib/active_record/relation.rb, line 445
def scoping(all_queries: nil, &block)
registry = klass.scope_registry
if global_scope?(registry) && all_queries == false
raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
elsif already_in_scope?(registry)
yield
else
_scoping(self, registry, all_queries, &block)
end
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
Если all_queries: true передано, ограничения будут применяться ко всем запросам для отношения, включая update и delete для экземпляров. После того, как all_queries установлено в true, его нельзя установить в false вложенном блоке.
Пожалуйста, используйте unscoped, если хотите удалить все предыдущие ограничения (включая default_scope) во время выполнения блока.
# File activerecord/lib/active_record/relation.rb, line 274
def size
if loaded?
records.length
else
count(:all)
end
end Возвращает размер набора записей.
# File activerecord/lib/active_record/relation.rb, line 258 def to_ary records.dup end
Преобразует объекты отношения в Array.
# File activerecord/lib/active_record/relation.rb, line 756
def to_sql
@to_sql ||= if eager_loading?
apply_join_dependency do |relation, join_dependency|
relation = join_dependency.apply_column_aliases(relation)
relation.to_sql
end
else
conn = klass.connection
conn.unprepared_statement { conn.to_sql(arel) }
end
end Возвращает SQL-запрос для отношения.
User.where(name: 'Oscar').to_sql # SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
# File activerecord/lib/active_record/relation.rb, line 589 def touch_all(*names, time: nil) update_all klass.touch_attributes_with_time(*names, time: time) end
Обновляет все записи в текущем отношении, устанавливая атрибуты updated_at/updated_on на текущее время или указанное время. Не создает связанные модели, не запускает обратные вызовы Active Record или валидацию. Этот метод может принимать имена атрибутов и необязательный аргумент time. Если переданы имена атрибутов, они обновляются вместе с атрибутами updated_at/updated_on. Если аргумент time не передан, используется текущее время по умолчанию.
Примеры
# Touch all records Person.all.touch_all # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670'" # Touch multiple records with a custom attribute Person.all.touch_all(:created_at) # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670', \"created_at\" = '2018-01-04 22:55:23.132670'" # Touch multiple records with a specified time Person.all.touch_all(time: Time.new(2020, 5, 16, 0, 0, 0)) # => "UPDATE \"people\" SET \"updated_at\" = '2020-05-16 00:00:00'" # Touch records with scope Person.where(name: 'David').touch_all # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
# File activerecord/lib/active_record/relation.rb, line 492
def update_all(updates)
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
return 0 if @none
if updates.is_a?(Hash)
if klass.locking_enabled? &&
!updates.key?(klass.locking_column) &&
!updates.key?(klass.locking_column.to_sym)
attr = table[klass.locking_column]
updates[attr.name] = _increment_attribute(attr)
end
values = _substitute_values(updates)
else
values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
end
arel = eager_loading? ? apply_join_dependency.arel : build_arel
arel.source.left = table
group_values_arel_columns = arel_columns(group_values.uniq)
having_clause_ast = having_clause.ast unless having_clause.empty?
stmt = arel.compile_update(values, table[primary_key], having_clause_ast, group_values_arel_columns)
klass.connection.update(stmt, "#{klass} Update All").tap { reset }
end Обновляет все записи в текущем отношении с предоставленными данными. Этот метод строит одно SQL-утверждение UPDATE и отправляет его напрямую в базу данных. Не создает связанные модели и не запускает обратные вызовы Active Record или валидацию. Однако значения, переданные в update_all, все равно будут проходить стандартную обработку типов и сериализацию Active Record. Возвращает количество измененных строк.
Примечание: Поскольку обратные вызовы Active Record не вызываются, этот метод не будет автоматически обновлять столбцы updated_at/updated_on.
Параметры
-
updates- Строка, массив или хэш, представляющие часть SET SQL-запроса. Любые предоставленные строки будут приведены к типу, если вы не используетеArel.sql. (Не передавайте значения, предоставленные пользователем, вArel.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')
# Update all invoices and set the number column to its id value.
Invoice.update_all('number = id')
# Update all books with 'Rails' in their title
Book.where('title LIKE ?', '%Rails%').update_all(title: Arel.sql("title + ' - volume 1'"))
# File activerecord/lib/active_record/relation.rb, line 546
def update_counters(counters)
touch = counters.delete(:touch)
updates = {}
counters.each do |counter_name, value|
attr = table[counter_name]
updates[attr.name] = _increment_attribute(attr, value)
end
if touch
names = touch if touch != true
names = Array.wrap(names)
options = names.extract_options!
touch_updates = klass.touch_attributes_with_time(*names, **options)
updates.merge!(touch_updates) unless touch_updates.empty?
end
update_all updates
end Обновляет счётчики записей в текущем отношении.
Параметры
-
counter-Hashсодержащий имена полей для обновления в качестве ключей и количество для обновления в качестве значений. -
:touchопция - Обновить столбцы временных меток при обновлении. -
Если имена атрибутов переданы, они обновляются вместе с атрибутами update_at/on.
Примеры
# For Posts by a given author increment the comment_count by 1. Post.where(author_id: author.id).update_counters(comment_count: 1)
# File activerecord/lib/active_record/relation.rb, line 823 def values @values.dup end
Защищенные методы экземпляров
# File activerecord/lib/active_record/relation.rb, line 872 def load_records(records) @records = records.freeze @loaded = true end
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.