2011-05-12 112 views

回答

24

你可能会得到一些很好的利用了Amoeba gem的ActiveRecord的3.2。

它支持的has_onehas_manyhas_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 

每个这些不同的选项应该重新导致将新帖子与旧帖子的标签重新关联,但没有重复评论。

变形虫也将自动递归到子记录,如果你让他们

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

哇这个宝石真的很棒。我不得不推出我自己的复制系统,它不能正常工作,但你的宝石工作得很好。 – Amala 2012-04-12 01:05:05

+3

该示例中的.dup应该是“new_post = my_post.amoeba_dup”,如文档中所定义的那样? – kibaekr 2014-01-31 08:04:51

+5

@kibaekr从README历史记录我发现“截至2012年12月11日,Amoeba不再覆盖内置的ActiveRecord :: Base#dup'方法,而是实现了自己的方法,名为'amoeba_dup' ...” – Sam 2016-03-31 13:44:46

18

您需要编写自己的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 
+20

你会得到一个破碎的原始对象,因为这'new_blerg.foos = self.foos'偷了你的协会。你也需要克隆它们。 – RocketR 2011-10-26 10:48:22

+1

这是最好的答案。按照我的愚见,在这种情况下滚动自己,比使用宝石更清洁,更容易,不那么神奇。 – hellion 2014-05-17 02:59:51

+0

RocketR - 好点。我认为我假设.foos关系是“拥有并且属于许多”,在这种情况下它可以很好,但如果foo属于blerg,那么是的,它会改变相关的foos。 – 2014-05-19 09:40:14

15

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

只是

gem ‘deep_cloneable’, ‘~> 1.4.0’

然后:

pirate.deep_clone :include => :mateys

+3

我发现这个比'amoeba'更容易实现 - 模型中不需要声明。 – benjineer 2016-03-01 04:42:22

+1

是的,这比ameoba的开销小得多,没有声明或dsl来学习。我认为它也更“高尚”。灵活性也很强。 Rails应该只是将其添加为AR方法。 – bwest87 2016-03-02 22:13:15

+1

新宠最喜欢的宝石。 – 2017-03-14 14:55:57