克隆rails中的记录,是否可以克隆关联和深层复制?

Min*_*ure 31 activerecord clone ruby-on-rails duplicates deep-copy

我是.在铁路上抓住一条记录......

  new_blerg = Blerg.find(1).clone
Run Code Online (Sandbox Code Playgroud)

此记录具有负载和负载的关联,并且这些关联甚至具有关联.

有没有办法深度复制记录并克隆它,以便克隆所有这些关联?

Vau*_*hon 29

对于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)

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

请享用!:)

  • 来自README历史的@kibaekr我发现"截至2012年12月11日,Amoeba不再覆盖内置的`ActiveRecord :: Base#dup`方法,而是实现自己的方法`amoeba_dup` ......" (5认同)
  • 示例中的.dup应该是"new_post = my_post.amoeba_dup",如文档中所定义的那样? (3认同)
  • 哇,这颗宝石真的很棒。我不得不推出自己的复制系统,但该系统无法正常工作,但您的宝石工作得很好。 (2认同)

Max*_*ams 20

您需要编写自己的clone_with_associations方法,该方法通过特定列出的关联集.从理论上讲,你可以编写一些使用reflect_on_all_associations的泛型,但你需要在关联的对象上做同样的事情,这将不可避免地最终创建一个生成无限量记录的循环.

所以,只需编写自己的.就像是

  #in Blerg
  has_many :foos
  has_many :bars #bars also have many chickens which we want to copy over as well
  def clone_with_associations
    new_blerg = self.dup
    new_blerg.save
    #simple association
    new_blerg.foos = self.foos
    #two-level association 
    self.bars.each do |bar|
      new_bar = bar.clone
      new_bar.save
      new_bar.chickens = bar.chickens 
      new_blerg.bars << bar
    end
    new_blerg
  end
Run Code Online (Sandbox Code Playgroud)

现在你可以做到

@new_blerg = Blerg.find(1).clone_with_associations
Run Code Online (Sandbox Code Playgroud)

  • 你会得到一个破碎的原始对象,因为这个`new_blerg.foos = self.foos`会窃取你的关联.你也需要克隆它们. (22认同)

Rob*_*Rob 16

同样,这个宝石似乎运作良好:https://github.com/moiristo/deep_cloneable,并且非常容易使用.

只是

gem ‘deep_cloneable’, ‘~> 1.4.0’

然后:

pirate.deep_clone :include => :mateys

  • 我发现这比`amoeba`更容易实现 - 模型中不需要声明. (3认同)