I've got an incoming SOAP request that tries to create or update nested resources. The incoming resources already have an ID that I'd like to use as my own, instead of generating a new one. Before I go any further, let me provide you with some context.
I've got the following models:
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
The problem that I have occurs when creating new resources, so assume the database is completely blank at the start of every code block. I already transformed the incoming data so it matches the Rails format.
# 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,
}],
}
When creating a non-nested resource you can provide an id (assuming it's not taken) and it will be saved with the provided id.
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.
However the above doesn't work for nested resources when using the accept nested attributes interface for the update method.
article = Article.find_or_initialize_by(id: data[:id])
article.update(data)
ActiveRecord::RecordNotFound: Couldn't find AccountedTime with ID=12345 for Article with ID=1234
The result I'm trying to achieve is to create the resources with their provided id. I thought I might have overlooked an option to toggle some sort of find_or_initialize_by or find_or_create_by mode when providing nested attributes. Am I missing something here?
I'm currently using the following alternative (without error handling for simplicity):
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
I think that your problem is not accepts_nested_attributes_for
configuration, which seems to be ok.
Maybe your problem is because you are using a reserved word for the Time
model. Try to change the name of the model and test it again.
UPDATE:
That seems pretty weird, but looking for the same problem I found this answer that explains a possible reason for the error in Rails 3 and show two possible solutions. Feel free to check it out, hope it helps.