Rails accept_nested_attributes创建具有特定ID的新资源

时间:2018-09-07 16:55:00

标签: ruby-on-rails nested-attributes

我有一个传入的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将与提供的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.

但是,当使用update方法的接受嵌套属性接口时,上述方法不适用于嵌套资源。

article = Article.find_or_initialize_by(id: data[:id])
article.update(data)
  

ActiveRecord :: RecordNotFound:找不到ID = 1234的文章的ID = 12345的AccountedTime

我要实现的结果是使用提供的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

1 个答案:

答案 0 :(得分:0)

我认为您的问题不是accepts_nested_attributes_for配置,这似乎没问题。

也许您的问题是因为您在Time模型中使用了reserved word。尝试更改模型的名称,然后再次进行测试。

更新:

这似乎很奇怪,但是在寻找同样的问题时,我发现this answer解释了Rails 3中错误的可能原因,并给出了两种可能的解决方案。随时检查一下,希望对您有所帮助。