модуль ActiveRecord::Persistence::ClassMethods
Методы экземпляров публичного интерфейса
# File activerecord/lib/active_record/persistence.rb, line 33
def create(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
else
object = new(attributes, &block)
object.save
object
end
end Создает объект (или несколько объектов) и сохраняет его в базе данных, если проходят валидации. Результирующий объект возвращается, независимо от того, был ли объект успешно сохранен в базе данных или нет.
Параметр attributes может быть либо Hash, либо Array массивом хешей. Эти хеши описывают атрибуты объектов, которые должны быть созданы.
Примеры
# Create a single new object
User.create(first_name: 'Jamie')
# Create an Array of new objects
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
# Create a single object and pass it into a block to set other attributes.
User.create(first_name: 'Jamie') do |u|
u.is_admin = false
end
# Creating an Array of new objects using a block, where the block is executed for each object:
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
u.is_admin = false
end
# File activerecord/lib/active_record/persistence.rb, line 50
def create!(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create!(attr, &block) }
else
object = new(attributes, &block)
object.save!
object
end
end Создает объект (или несколько объектов) и сохраняет его в базе данных, если проходят валидации. Вызывает исключение RecordInvalid, если валидации не пройдены, в отличие от Base#create.
Параметр attributes может быть либо Hash, либо Array массивом хешей. Эти хеши описывают атрибуты, которые будут созданы для объекта или нескольких объектов, если задан Array массивов хешей.
# File activerecord/lib/active_record/persistence.rb, line 474 def delete(id_or_array) delete_by(primary_key => id_or_array) end
Удаляет строку с первичным ключом, соответствующим аргументу id, используя SQL-запрос DELETE, и возвращает количество удаленных строк. Объекты Active Record не создаются, поэтому колбэки объекта не выполняются, включая любые :dependent параметры ассоциаций.
Вы можете удалить несколько строк сразу, передав Array массив id.
Примечание: Хотя это часто намного быстрее, чем альтернатива, destroy, пропуск колбэков может обойти бизнес-логику в вашем приложении, которая обеспечивает целостность ссылок или выполняет другие важные задачи.
Примеры
# Delete a single row Todo.delete(1) # Delete multiple rows Todo.delete([2,3,4])
# File activerecord/lib/active_record/persistence.rb, line 448
def destroy(id)
if id.is_a?(Array)
find(id).each(&:destroy)
else
find(id).destroy
end
end Уничтожает объект (или несколько объектов) с заданным идентификатором. Объект сначала создается, поэтому все колбэки и фильтры срабатывают, прежде чем объект будет удален. Этот метод менее эффективен, чем delete, но позволяет запускать методы очистки и другие действия.
В сущности, этот метод находит объект (или несколько объектов) с заданным идентификатором, создает новый объект из атрибутов и затем вызывает destroy на нём.
Параметры
-
id- Это должен быть идентификатор или массив идентификаторов для уничтожения.
Примеры
# Destroy a single object Todo.destroy(1) # Destroy multiple objects todos = [1,2,3] Todo.destroy(todos)
# File activerecord/lib/active_record/persistence.rb, line 66 def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil) insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps) end
Вставляет один запрос в базу данных в одном SQL-выражении INSERT. Он не создаёт никаких моделей и не вызывает колбэки или валидации Active Record. Хотя переданные значения проходят через типизацию и сериализацию Active Record.
См. ActiveRecord::Persistence#insert_all для документации.
# File activerecord/lib/active_record/persistence.rb, line 155 def insert!(attributes, returning: nil, record_timestamps: nil) insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps) end
Вставляет один запрос в базу данных в одном SQL-выражении INSERT. Он не создаёт никаких моделей и не вызывает колбэки или валидации Active Record. Хотя переданные значения проходят через типизацию и сериализацию Active Record.
См. ActiveRecord::Persistence#insert_all! для более подробной информации.
# File activerecord/lib/active_record/persistence.rb, line 145 def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil) InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute end
Вставляет несколько записей в базу данных в одном SQL-выражении INSERT. Он не создаёт никаких моделей и не вызывает колбэки или валидации Active Record. Хотя переданные значения проходят через типизацию и сериализацию Active Record.
Параметр attributes — это Array массив хешей. Каждый Hash определяет атрибуты для одной строки и должен иметь одинаковые ключи.
Строки считаются уникальными по каждому уникальному индексу в таблице. Любые дублирующие строки пропускаются. Замените с помощью :unique_by (см. ниже).
Возвращает ActiveRecord::Result с содержимым, основанным на :returning (см. ниже).
Параметры
- :returning
-
(Только PostgreSQL) Массив атрибутов, которые нужно вернуть для всех успешно вставленных записей, по умолчанию — первичный ключ. Передайте
returning: %w[ id name ]для id и имени илиreturning: false, чтобы полностью пропустить подзапросRETURNINGSQL.Также можно передать строку SQL, если вам нужно больше контроля над значениями возврата (например,
returning: "id, name as new_name"). - :unique_by
-
(Только PostgreSQL и SQLite) По умолчанию строки считаются уникальными по каждому уникальному индексу в таблице. Любые дублирующие строки пропускаются.
Чтобы пропустить строки в соответствии только с одним уникальным индексом, передайте
:unique_by.Рассмотрим модель книги, где дублирование ISBN не имеет смысла, но если какая-либо строка имеет существующий id или не уникальна по другому уникальному индексу, возникает
ActiveRecord::RecordNotUnique.Уникальные индексы могут быть определены по столбцам или имени:
unique_by: :isbn unique_by: %i[ author_id name ] unique_by: :index_books_on_isbn
- :record_timestamps
-
По умолчанию автоматическое задание столбцов со временем контролируется конфигурацией модели
record_timestamps, соответствующей типичному поведению.Чтобы переопределить это и принудительно установить столбцы со временем одним или другим способом, передайте
:record_timestamps:record_timestamps: true # Always set timestamps automatically record_timestamps: false # Never set timestamps automatically
Поскольку он полагается на информацию об индексе из базы данных, :unique_by рекомендуется использовать вместе с кэшем схемы Active Record.
Пример
# Insert records and skip inserting any duplicates.
# Here "Eloquent Ruby" is skipped because its id is not unique.
Book.insert_all([
{ id: 1, title: "Rework", author: "David" },
{ id: 1, title: "Eloquent Ruby", author: "Russ" }
])
# insert_all works on chained scopes, and you can use create_with
# to set default attributes for all inserted records.
author.books.create_with(created_at: Time.now).insert_all([
{ id: 1, title: "Rework" },
{ id: 2, title: "Eloquent Ruby" }
])
# File activerecord/lib/active_record/persistence.rb, line 213 def insert_all!(attributes, returning: nil, record_timestamps: nil) InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps).execute end
Вставляет несколько записей в базу данных в одном SQL-выражении INSERT. Он не создаёт никаких моделей и не вызывает колбэки или валидации Active Record. Хотя переданные значения проходят через типизацию и сериализацию Active Record.
Параметр attributes — это Array массив хешей. Каждый Hash определяет атрибуты для одной строки и должен иметь одинаковые ключи.
Вызывает ActiveRecord::RecordNotUnique если какие-либо строки нарушают уникальный индекс в таблице. В этом случае никакие строки не вставляются.
Чтобы пропустить дублирующие строки, см. ActiveRecord::Persistence#insert_all. Чтобы их заменить, см. ActiveRecord::Persistence#upsert_all.
Возвращает ActiveRecord::Result с содержимым, основанным на :returning (см. ниже).
Параметры
- :returning
-
(Только PostgreSQL) Массив атрибутов, которые нужно вернуть для всех успешно вставленных записей, по умолчанию — первичный ключ. Передайте
returning: %w[ id name ]для id и имени илиreturning: false, чтобы полностью пропустить подзапросRETURNINGSQL.Также можно передать строку SQL, если вам нужно больше контроля над значениями возврата (например,
returning: "id, name as new_name"). - :record_timestamps
-
По умолчанию автоматическое задание столбцов со временем контролируется конфигурацией модели
record_timestamps, соответствующей типичному поведению.Чтобы переопределить это и принудительно установить столбцы со временем одним или другим способом, передайте
:record_timestamps:record_timestamps: true # Always set timestamps automatically record_timestamps: false # Never set timestamps automatically
Примеры
# Insert multiple records
Book.insert_all!([
{ title: "Rework", author: "David" },
{ title: "Eloquent Ruby", author: "Russ" }
])
# Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
# does not have a unique id.
Book.insert_all!([
{ id: 1, title: "Rework", author: "David" },
{ id: 1, title: "Eloquent Ruby", author: "Russ" }
])
# File activerecord/lib/active_record/persistence.rb, line 347
def instantiate(attributes, column_types = {}, &block)
klass = discriminate_class_for_record(attributes)
instantiate_instance_of(klass, attributes, column_types, &block)
end Принимая хеш атрибутов, instantiate возвращает новый экземпляр соответствующего класса. Принимает только ключи в виде строк.
Например, Post.all может вернуть Comments, Messages и Emails, сохраняя подкласс записи в type атрибуте. Вызывая instantiate вместо new, методы поиска гарантируют, что они получают новые экземпляры соответствующего класса для каждой записи.
См. ActiveRecord::Inheritance#discriminate_class_for_record для того, как реализуется это отображение наследования «одной таблицы».
# File activerecord/lib/active_record/persistence.rb, line 379
def update(id = :all, attributes)
if id.is_a?(Array)
if id.any?(ActiveRecord::Base)
raise ArgumentError,
"You are passing an array of ActiveRecord::Base instances to `update`. " \
"Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`."
end
id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
object.update(attributes[idx])
}
elsif id == :all
all.each { |record| record.update(attributes) }
else
if ActiveRecord::Base === id
raise ArgumentError,
"You are passing an instance of ActiveRecord::Base to `update`. " \
"Please pass the id of the object by calling `.id`."
end
object = find(id)
object.update(attributes)
object
end
end Обновляет объект (или несколько объектов) и сохраняет его в базе данных, если пройдена валидация. Результирующий объект возвращается, независимо от успешного сохранения объекта в базе данных или нет.
Параметры
-
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)
# Updates multiple records from the result of a relation
people = Person.where(group: "expert")
people.update(group: "masters")
Примечание: обновление большого количества записей выполнит запрос UPDATE для каждой записи, что может привести к проблемам производительности. Когда вызов обратных вызовов не нужен для каждого обновления записи, предпочтительнее использовать update_all для обновления всех записей в одном запросе.
# File activerecord/lib/active_record/persistence.rb, line 405
def update!(id = :all, attributes)
if id.is_a?(Array)
if id.any?(ActiveRecord::Base)
raise ArgumentError,
"You are passing an array of ActiveRecord::Base instances to `update!`. " \
"Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`."
end
id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
object.update!(attributes[idx])
}
elsif id == :all
all.each { |record| record.update!(attributes) }
else
if ActiveRecord::Base === id
raise ArgumentError,
"You are passing an instance of ActiveRecord::Base to `update!`. " \
"Please pass the id of the object by calling `.id`."
end
object = find(id)
object.update!(attributes)
object
end
end Обновляет объект (или несколько объектов) так же, как update, но вызывает update! вместо update, поэтому исключение генерируется, если запись недействительна, и сохранение завершится неудачей.
# File activerecord/lib/active_record/persistence.rb, line 223 def upsert(attributes, on_duplicate: :update, returning: nil, unique_by: nil, record_timestamps: nil) upsert_all([ attributes ], on_duplicate: on_duplicate, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps) end
Обновляет или вставляет (upsert) одну запись в базу данных в одном операторе SQL INSERT. Он не создает экземпляры моделей и не запускает обратные вызовы или валидацию Active Record. Хотя переданные значения проходят через преобразование типов и сериализацию Active Record.
См. ActiveRecord::Persistence#upsert_all для документации.
# File activerecord/lib/active_record/persistence.rb, line 333 def upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil) InsertAll.new(self, attributes, on_duplicate: on_duplicate, update_only: update_only, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute end
Обновляет или вставляет (upsert) несколько записей в базу данных в одном операторе SQL INSERT. Он не создает экземпляры моделей и не запускает обратные вызовы или валидацию Active Record. Хотя переданные значения проходят через преобразование типов и сериализацию Active Record.
Параметр attributes является Array массивом хэшей. Каждый Hash определяет атрибуты для одной строки и должен иметь одинаковые ключи.
Возвращает ActiveRecord::Result со своим содержимым, основанным на :returning (см. ниже).
По умолчанию, upsert_all будет обновлять все столбцы, которые могут быть обновлены при конфликте. Это все столбцы, кроме первичных ключей, столбцов только для чтения и столбцов, охваченных необязательным unique_by.
Параметры
- :returning
-
(Только PostgreSQL) Массив атрибутов для возврата всех успешно вставленных записей, по умолчанию это первичный ключ. Передайте
returning: %w[ id name ]для id и name илиreturning: falseчтобы полностью исключить подлежащуюRETURNINGSQL-строку.Вы также можете передать строку SQL, если вам нужен больший контроль над возвращаемыми значениями (например,
returning: "id, name as new_name"). - :unique_by
-
(Только PostgreSQL и SQLite) По умолчанию строки считаются уникальными по каждому уникальному индексу в таблице. Любые дублирующиеся строки пропускаются.
Чтобы пропустить строки только по одному уникальному индексу, передайте
:unique_by.Рассмотрим модель Book, где дублирование ISBN не имеет смысла, но если какая-либо строка имеет существующий id или не уникальна по другому уникальному индексу,
ActiveRecord::RecordNotUniqueбудет поднято.Уникальные индексы могут быть определены по столбцам или имени:
unique_by: :isbn unique_by: %i[ author_id name ] unique_by: :index_books_on_isbn
Поскольку он полагается на информацию об индексе из базы данных, :unique_by рекомендуется использовать в паре с кешем схемы Active Record.
- :on_duplicate
-
Настройте SQL-предложение обновления, которое будет использоваться в случае конфликта.
ПРИМЕЧАНИЕ: Если вы используете этот параметр, вы должны сами указать все столбцы, которые хотите обновить.
Пример:
Commodity.upsert_all( [ { id: 2, name: "Copper", price: 4.84 }, { id: 4, name: "Gold", price: 1380.87 }, { id: 6, name: "Aluminium", price: 0.35 } ], on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)") )См. связанный параметр
:update_only. Оба параметра не могут использоваться одновременно. - :update_only
-
Укажите список имен столбцов, которые будут обновлены в случае конфликта. Если не указано,
upsert_allбудет обновлять все столбцы, которые могут быть обновлены. Это все столбцы, кроме первичных ключей, столбцов только для чтения и столбцов, охваченных необязательнымunique_by.Пример:
Commodity.upsert_all( [ { id: 2, name: "Copper", price: 4.84 }, { id: 4, name: "Gold", price: 1380.87 }, { id: 6, name: "Aluminium", price: 0.35 } ], update_only: [:price] # Only prices will be updated )См. связанный параметр
:on_duplicate. Оба параметра не могут использоваться одновременно. - :record_timestamps
-
По умолчанию автоматическое назначение столбцов временных отметок контролируется конфигурацией модели
record_timestamps, что соответствует типичному поведению.Чтобы переопределить это и принудительно установить столбцы временных отметок одним способом или другим, передайте
:record_timestamps:record_timestamps: true # Always set timestamps automatically record_timestamps: false # Never set timestamps automatically
Примеры
# Inserts multiple records, performing an upsert when records have duplicate ISBNs.
# Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
Book.upsert_all([
{ title: "Rework", author: "David", isbn: "1" },
{ title: "Eloquent Ruby", author: "Russ", isbn: "1" }
], unique_by: :isbn)
Book.find_by(isbn: "1").title # => "Eloquent Ruby"
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.