У меня есть входящий SOAP-запрос, который пытается создать или обновить вложенные ресурсы. Входящие ресурсы уже имеют идентификатор, который я хотел бы использовать как свой собственный, вместо создания нового. Прежде чем идти дальше, позвольте мне представить вам некоторый контекст.
У меня есть следующие модели:
class AccountedTime < ApplicationRecord
belongs_to :article, optional: false
end
class Article < ApplicationRecord
has_many :accounted_times, dependent: :destroy
accepts_nested_attributes_for :accounted_times, allow_destroy: true
end
Проблема, с которой я сталкиваюсь при создании новых ресурсов, поэтому предположим, что база данных полностью пуста в начале каждого блока кода. Я уже преобразовал входящие данные, чтобы они соответствовали формату Rails.
# transformed incoming data
data = {
id: 1234,
title: '...',
body: '...',
accounted_times_attributes: [{
id: 12345,
units: '1.3'.to_d,
type: 'work',
billable: true,
}, {
id: 12346,
units: '0.2'.to_d,
type: 'travel',
billable: false,
}],
}
При создании не вложенного ресурса вы можете указать идентификатор (при условии, что он не занят), и он будет сохранен с предоставленным идентификатором.
article = Article.find_or_initialize_by(id: data[:id])
article.update(data.except(:accounted_times_attributes))
# The above will save and create a record with id 1234.
Однако приведенное выше не работает для вложенных ресурсов при использовании интерфейса приема вложенных атрибутов для метода обновления.
article = Article.find_or_initialize_by(id: data[:id])
article.update(data)
ActiveRecord :: RecordNotFound: Не удалось найти AccountsTime с идентификатором = 12345 для статьи с идентификатором = 1234
В результате я пытаюсь создать ресурсы с указанным идентификатором. Я подумал, что мог пропустить опцию переключения какого-либо режима find_or_initialize_by или find_or_create_by при предоставлении вложенных атрибутов. Я что-то здесь упускаю?
В настоящее время я использую следующую альтернативу (без простоты обработки ошибок):
article = Article.find_or_initialize_by(id: data[:id])
article.update(data.except(:accounted_times_attributes))
data[:accounted_times_attributes]&.each do |attrs|
accounted_time = article.accounted_times.find_or_initialize_by(id: attrs[:id])
accounted_time.update(attrs)
end