Ruby on Rails深度复制/深层克隆对象及其属性

我想对包括所有属性的对象进行深层复制。

experiment_old有10个试验。 我希望通过10次试验将所有内容复制到experiment_new中。 experiment_old还应保留10个试用信息。

但是,我在下面尝试过的所有情况都会很好地复制一切,但是experiment_old没有10个试验信息。 他们只是出现在experiment_new上。

对这些案例进行深层复制的最佳方法是什么。

情况1:

@experiment_new = Experiment.create(@experiment_old.attributes.merge(:trials => experiment_old.trails)) 

案例2:

 @experiment_new = Marshal.load(Marshal.dump(@experiment_old.trials)) 

案例3:

 @experiment_new = @experiment_old.clone 

这是模型:

 class Experiment < ActiveRecord::Base belongs_to :experimenter has_many :trials has_many :participants end class Trial < ActiveRecord::Base belongs_to :experiment belongs_to :datum belongs_to :condition has_one :result_trial end 

您应该克隆每个试验并将它们分配给克隆的实验:

 @experiment_new = @experiment_old.clone @experiment_old.trials.each do |trial| @experiment_new.trials << trial.clone end 

您可以享受ActiveRecord 3.2的Amoebagem 。

它支持has_onehas_manyhas_and_belongs_to_many关联的简单和自动递归复制,字段预处理以及可以同时应用于模型和动态的高度灵活且function强大的配置DSL。

请务必查看Amoeba文档,但使用非常简单……

只是

 gem install amoeba 

或添加

 gem 'amoeba' 

到您的Gemfile

然后将变形虫块添加到模型中并像往常一样运行dup方法

 class Post < ActiveRecord::Base has_many :comments has_and_belongs_to_many :tags amoeba do enable end end class Comment < ActiveRecord::Base belongs_to :post end class Tag < ActiveRecord::Base has_and_belongs_to_many :posts end class PostsController < ActionController def some_method my_post = Post.find(params[:id]) new_post = my_post.dup new_post.save end end 

您的新post应该包含最初与之关联的所有标记,并且所有评论也应该重复。 您可以通过DSL禁用各种记录的复制,您可以在文档中阅读这些记录,但是,例如,如果您想保留标记,而不是注释,则可以执行以下操作:

 class Post < ActiveRecord::Base has_many :comments has_and_belongs_to_many :tags amoeba do include_field :comments end end 

或使用独家语法

 class Post < ActiveRecord::Base has_many :comments has_and_belongs_to_many :tags amoeba do exclude_field :comments end end 

或者通过指定要识别的字段类型(从而复制)

 class Post < ActiveRecord::Base has_many :comments has_and_belongs_to_many :tags amoeba do recognize :has_and_belongs_to_many end end 

这些不同选项中的每一个都应该导致重新关联新post与旧post相同的标签,但不会重复评论。

如果启用,Amoeba也会自动递归到子记录中

 class Post < ActiveRecord::Base has_many :comments amoeba do enable end end class Comment < ActiveRecord::Base belongs_to :post has_many :ratings amoeba do enable end end class Rating < ActiveRecord::Base belongs_to :comment end 

您还可以在字段前添加一些额外数据以指示唯一性

 class Post < ActiveRecord::Base has_many :comments amoeba do enable prepend :title => "Copy of " end end 

除了前置之外,您还可以在给定字段上附加或运行正则表达式

请享用! 🙂