我是。在铁轨中抓住一条记录......
new_blerg = Blerg.find(1).clone
此记录包含大量关联,这些关联甚至还有关联。
有没有办法对记录进行深层复制并克隆它,以便克隆所有这些关联?
答案 0 :(得分:29)
对于ActiveRecord 3.2,您可以从Amoeba gem中获得一些好用。
它支持has_one
,has_many
和has_and_belongs_to_many
关联的简单和自动递归复制,字段预处理以及高度灵活且功能强大的配置DSL,可以应用于模型和苍蝇。
请务必查看Amoeba Documentation,但使用非常简单......
刚
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
您的新帖子应该包含最初与之关联的所有标记,并且所有评论也应该重复。您可以通过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
这些不同的选项中的每一个都应该使新帖子与旧帖子重新关联,但不会重复评论。
如果您启用了Amoeba,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
除了前置之外,您还可以在给定字段上附加或运行正则表达式
享受! :)
答案 1 :(得分: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
现在你可以做到
@new_blerg = Blerg.find(1).clone_with_associations
答案 2 :(得分:16)
同样,这个宝石似乎运作良好:https://github.com/moiristo/deep_cloneable,并且非常易于使用。
只需
gem ‘deep_cloneable’, ‘~> 1.4.0’
然后:
pirate.deep_clone :include => :mateys