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

shc*_*hci 17 ruby-on-rails deep-copy

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

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))
Run Code Online (Sandbox Code Playgroud)

案例2:

@experiment_new = Marshal.load(Marshal.dump(@experiment_old.trials))
Run Code Online (Sandbox Code Playgroud)

案例3:

@experiment_new = @experiment_old.clone
Run Code Online (Sandbox Code Playgroud)

这是模型:

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
Run Code Online (Sandbox Code Playgroud)

Vau*_*hon 24

您可以享受ActiveRecord 3.2 的Amoeba宝石.

它支持的简单和自动递归重复has_one,has_manyhas_and_belongs_to_many协会,现场预处理和既能对模型和动态应用了灵活而强大的配置DSL.

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

只是

gem install amoeba
Run Code Online (Sandbox Code Playgroud)

或添加

gem 'amoeba'
Run Code Online (Sandbox Code Playgroud)

到你的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
Run Code Online (Sandbox Code Playgroud)

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

class Post < ActiveRecord::Base
  has_many :comments
  has_and_belongs_to_many :tags

  amoeba do
    include_field :comments
  end
end
Run Code Online (Sandbox Code Playgroud)

或使用独有的语法

class Post < ActiveRecord::Base
  has_many :comments
  has_and_belongs_to_many :tags

  amoeba do
    exclude_field :comments
  end
end
Run Code Online (Sandbox Code Playgroud)

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

class Post < ActiveRecord::Base
  has_many :comments
  has_and_belongs_to_many :tags

  amoeba do
    recognize :has_and_belongs_to_many
  end
end
Run Code Online (Sandbox Code Playgroud)

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

如果启用,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
Run Code Online (Sandbox Code Playgroud)

您还可以使用一些额外数据为字段添加前缀以指示唯一性

class Post < ActiveRecord::Base
  has_many :comments

  amoeba do
    enable
    prepend :title => "Copy of "
  end
end
Run Code Online (Sandbox Code Playgroud)

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

请享用!:)

  • 你的例子中不应该是`include_field:tags`吗?当你想要不复制它们时,包含这些注释对我来说没有意义. (3认同)

Mic*_*ant 22

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

@experiment_new = @experiment_old.clone
@experiment_old.trials.each do |trial|
  @experiment_new.trials << trial.clone
end
Run Code Online (Sandbox Code Playgroud)