2011-05-12 115 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