Spec-Zone.ru › Ruby on Rails 7.0

модуль ActiveRecord::AutosaveAssociation

Ассоциация Active Record с автоматическим сохранением

AutosaveAssociation — это модуль, который отвечает за автоматическое сохранение связанных записей при сохранении родительской записи. Помимо сохранения, он также удаляет любые связанные записи, помеченные на удаление. (См. mark_for_destruction и marked_for_destruction?).

Сохранение родителя, его ассоциаций и удаление помеченных ассоциаций происходит внутри транзакции. Это никогда не должно оставлять базу данных в несогласованном состоянии.

Если проверки для какой-либо из ассоциаций не пройдут, их сообщения об ошибках будут применены к родителю.

Обратите внимание, что это также означает, что ассоциации, помеченные на удаление, не будут удалены непосредственно. Однако они по-прежнему будут помечены на удаление.

Обратите внимание, что autosave: false не эквивалентно отсутствию объявления :autosave. Если опция :autosave отсутствует, то новые записи ассоциаций сохраняются, но обновленные записи ассоциаций не сохраняются.

Проверка

Записи дочерних элементов проверяются, если :validate не false.

Callbacks

Ассоциация с опцией autosave определяет несколько обратных вызовов в вашей модели (around_save, before_save, after_create, after_update). Обратите внимание, что обратные вызовы выполняются в порядке их определения в модели. Следует избегать изменения содержимого ассоциации до выполнения обратных вызовов autosave. Размещение ваших обратных вызовов после ассоциаций обычно является хорошей практикой.

Пример «один ко одному»

class Post < ActiveRecord::Base
  has_one :author, autosave: true
end

Сохранение изменений в родительском и связанном элементе модели теперь можно выполнять автоматически и атомарно:

post = Post.find(1)
post.title       # => "The current global position of migrating ducks"
post.author.name # => "alloy"

post.title = "On the migration of ducks"
post.author.name = "Eloy Duran"

post.save
post.reload
post.title       # => "On the migration of ducks"
post.author.name # => "Eloy Duran"

Удаление связанного элемента модели в рамках действия сохранения родительского элемента выполняется так же просто, как пометка его на удаление:

post.author.mark_for_destruction
post.author.marked_for_destruction? # => true

Обратите внимание, что модель ещё не удалена из базы данных:

id = post.author.id
Author.find_by(id: id).nil? # => false

post.save
post.reload.author # => nil

Теперь модель удалена из базы данных:

Author.find_by(id: id).nil? # => true

Пример «один ко многим»

Когда :autosave не объявлена, новые дочерние элементы сохраняются при сохранении их родителя:

class Post < ActiveRecord::Base
  has_many :comments # :autosave option is not declared
end

post = Post.new(title: 'ruby rocks')
post.comments.build(body: 'hello world')
post.save # => saves both post and comment

post = Post.create(title: 'ruby rocks')
post.comments.build(body: 'hello world')
post.save # => saves both post and comment

post = Post.create(title: 'ruby rocks')
comment = post.comments.create(body: 'hello world')
comment.body = 'hi everyone'
post.save # => saves post, but not comment

Когда :autosave имеет значение true, все дочерние элементы сохраняются, независимо от того, являются ли они новыми записями или нет:

class Post < ActiveRecord::Base
  has_many :comments, autosave: true
end

post = Post.create(title: 'ruby rocks')
comment = post.comments.create(body: 'hello world')
comment.body = 'hi everyone'
post.comments.build(body: "good morning.")
post.save # => saves post and both comments.

Удаление одного из связанных элементов в рамках действия сохранения родителя выполняется так же просто, как пометка его на удаление:

post.comments # => [#<Comment id: 1, ...>, #<Comment id: 2, ...]>
post.comments[1].mark_for_destruction
post.comments[1].marked_for_destruction? # => true
post.comments.length # => 2

Обратите внимание, что модель ещё не удалена из базы данных:

id = post.comments.last.id
Comment.find_by(id: id).nil? # => false

post.save
post.reload.comments.length # => 1

Теперь модель удалена из базы данных:

Comment.find_by(id: id).nil? # => true

Ограничения

Обратите внимание, что autosave будет срабатывать только для уже сохранённых записей ассоциаций, если сами записи были изменены. Это необходимо для защиты от SystemStackError, вызванных циклическими проверками ассоциаций. Единственное исключение — если используется пользовательский контекст проверки, в этом случае проверки всегда будут выполняться для связанных записей.

Методы открытого экземпляра

changed_for_autosave?() Показать исходный код
# File activerecord/lib/active_record/autosave_association.rb, line 271
def changed_for_autosave?
  new_record? || has_changes_to_save? || marked_for_destruction? || nested_records_changed_for_autosave?
end

Возвращает значение true, если запись была изменена каким-либо образом (включая то, были ли изменены какие-либо вложенные ассоциации autosave).

destroyed_by_association() Показать исходный код
# File activerecord/lib/active_record/autosave_association.rb, line 265
def destroyed_by_association
  @destroyed_by_association
end

Возвращает ассоциацию родительского элемента, который удаляется.

Используется для предотвращения ненужного обновления счётчика кэша.

destroyed_by_association=(reflection) Показать исходный код
# File activerecord/lib/active_record/autosave_association.rb, line 258
def destroyed_by_association=(reflection)
  @destroyed_by_association = reflection
end

Записывает ассоциацию, которая уничтожается, и уничтожает запись в процессе.

mark_for_destruction() Показать исходный код
# File activerecord/lib/active_record/autosave_association.rb, line 245
def mark_for_destruction
  @marked_for_destruction = true
end

Помечает запись на удаление в рамках транзакции сохранения родителя. Это не фактически уничтожает запись мгновенно, а дочерняя запись будет уничтожена, когда будет вызвано parent.save.

Полезно только в том случае, если опция :autosave для родительского элемента включена для этой связанной модели.

marked_for_destruction?() Показать исходный код
# File activerecord/lib/active_record/autosave_association.rb, line 252
def marked_for_destruction?
  @marked_for_destruction
end

Возвращает значение true, если запись будет удалена в рамках транзакции сохранения родительского элемента.

Полезно только в том случае, если опция :autosave для родительского элемента включена для этой связанной модели.

reload(options = nil) Показать исходный код
# File activerecord/lib/active_record/autosave_association.rb, line 234
def reload(options = nil)
  @marked_for_destruction = false
  @destroyed_by_association = nil
  super
end

Перезагружает атрибуты объекта обычным образом и очищает флаг marked_for_destruction.

Вызывает метод суперкласса

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

Spec-Zone.ru

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