我的克隆方法是从原始模型中窃取孩子

我已就此问题查了一堆问题,包括这里 , 这里和这里 。 我似乎无法弄清楚这里出了什么问题。

这是我的复制方法:

def copy(new_period) copy = self.dup copy.report_id = Report.maximum(:report_id).next copy.period_id = new_period copy.responses = self.responses.dup copy.save end 

此方法正确地生成报表模型的副本,并按预期将其分配给新期间。 它还将所有孩子从原始报告移动到新报告而不重复,这是不期望的。 我不明白为什么会这样。

有人有主意吗?

我认为有罪的是以下几行

 copy.responses = self.responses.dup 

self.responses返回的值是ActiveRecord::Relation 。 当您调用dup时,您将复制关系实例,而不是范围指向的资源。

如果要复制响应对象,则需要先加载它们。

 copy.responses = self.responses.map { |response| response.dup } 

要么

 copy.responses = self.responses.map(&:dup) 

dup做一个浅拷贝。 它也不会复制其所有子对象。 这对于数组和散列也很重要。

解决方案是基本上为您的模型编写克隆方法:

 def clone(new_period) copy = self.class.new self.attributes.slice(*%w{attributes to copy}) copy.report_id = Report.maximum(:report_id).next copy.period_id = new_period copy.responses = Response.clone_multiple(self.responses) copy.save end 

与响应类似,添加一个类方法来克隆集合:

 class << self def clone_multiple(collection) collection.map do |response| copy = self.new(response.attributes.slice(*%w{attributes to clone}) copy.save copy end end end