【发布时间】:2011-08-24 00:24:56
【问题描述】:
我正在 .clone - 在 rails 中记录一条记录...
new_blerg = Blerg.find(1).clone
这条记录有很多关联,而且这些关联甚至还有关联。
有没有办法深度复制记录并克隆它,以便它也与所有这些关联一起克隆?
【问题讨论】:
标签: ruby-on-rails activerecord duplicates clone deep-copy
我正在 .clone - 在 rails 中记录一条记录...
new_blerg = Blerg.find(1).clone
这条记录有很多关联,而且这些关联甚至还有关联。
有没有办法深度复制记录并克隆它,以便它也与所有这些关联一起克隆?
【问题讨论】:
标签: ruby-on-rails activerecord duplicates clone deep-copy
您可以从Amoeba gem for ActiveRecord 3.2 中获得一些好处。
它支持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
您的新帖子应该包含最初与之关联的所有标签,并且所有 cmets 也应该被复制。您可以通过 DSL 禁用各种记录的重复,您可以在文档中阅读相关内容,但例如,如果您想保留标签,而不是 cmets,您可以执行以下操作:
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
这些不同的选项中的每一个都应该导致新帖子与旧帖子的标签相同,但不会复制 cmets。
如果您启用它们,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
除了前置之外,您还可以在给定字段上附加或运行正则表达式
享受吧! :)
【讨论】:
ActiveRecord::Base#dup 方法,而是实现了自己的名为 amoeba_dup 的方法...”跨度>
同样,这个 gem 似乎运行良好:https://github.com/moiristo/deep_cloneable,并且非常易于使用。
只是
gem ‘deep_cloneable’, ‘~> 1.4.0’
然后:
pirate.deep_clone :include => :mateys
【讨论】:
amoeba 更容易实现——模型中不需要声明。
您需要编写自己的 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
【讨论】:
new_blerg.foos = self.foos 窃取了你的关联。您还需要克隆它们。