Rails accept_nested_attributes 创建具有特定 ID 的新资源
Rails accept_nested_attributes creating a new resource with specific id
我收到一个试图创建或更新嵌套资源的传入 SOAP 请求。传入的资源已经有一个 ID,我想将其用作我自己的 ID,而不是生成一个新的 ID。在我继续之前,让我为您提供一些背景信息。
我有以下型号:
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,
}],
}
创建非嵌套资源时,您可以提供一个 ID(假设未被占用),它将与提供的 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.
但是,当使用更新方法的接受嵌套属性接口时,上述方法不适用于嵌套资源。
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
我想要达到的结果是使用提供的 ID 创建资源。我想我可能忽略了在提供嵌套属性时切换某种 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
我觉得你的问题不是accepts_nested_attributes_for
配置问题,好像没问题。
也许您的问题是因为您对 Time
模型使用了 reserved word。尝试更改模型的名称并再次测试。
更新:
这看起来很奇怪,但在寻找相同的问题时我发现 this answer 解释了 Rails 3 中错误的可能原因,并显示了两个可能的解决方案。随时查看,希望对您有所帮助。
我收到一个试图创建或更新嵌套资源的传入 SOAP 请求。传入的资源已经有一个 ID,我想将其用作我自己的 ID,而不是生成一个新的 ID。在我继续之前,让我为您提供一些背景信息。
我有以下型号:
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,
}],
}
创建非嵌套资源时,您可以提供一个 ID(假设未被占用),它将与提供的 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.
但是,当使用更新方法的接受嵌套属性接口时,上述方法不适用于嵌套资源。
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
我想要达到的结果是使用提供的 ID 创建资源。我想我可能忽略了在提供嵌套属性时切换某种 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
我觉得你的问题不是accepts_nested_attributes_for
配置问题,好像没问题。
也许您的问题是因为您对 Time
模型使用了 reserved word。尝试更改模型的名称并再次测试。
更新:
这看起来很奇怪,但在寻找相同的问题时我发现 this answer 解释了 Rails 3 中错误的可能原因,并显示了两个可能的解决方案。随时查看,希望对您有所帮助。