web-dev-qa-db-ja.com

Railsでレコードを複製する場合、関連付けとディープコピーを複製することはできますか?

Railsでレコードを.cloneしています...

  new_blerg = Blerg.find(1).clone

このレコードには、関連付けのロードとロードがあり、それらの関連付けには関連付けさえあります。

レコードをディープコピーして複製する方法はありますか?そうすれば、それらすべての関連付けも複製されますか?

31
MintDeparture

ActiveRecord 3.2の Amoeba gem をうまく利用できるかもしれません。

has_onehas_manyhas_and_belongs_to_manyの関連付けの簡単で自動な再帰的な複製、フィールドの前処理、およびモデルとオンザフライの両方に適用できる非常に柔軟で強力な構成DSLをサポートしています。

Amoeba Documentation を確認してください。ただし、使用方法は非常に簡単です...

ただ

gem install amoeba

または追加

gem 'amoeba'

あなたのGemfileに

次に、amoebaブロックをモデルに追加し、通常どおり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

また、先頭に追加することに加えて、特定のフィールドに正規表現を追加または実行することもできます

楽しい! :)

29
Vaughn Draughon

リストされた特定の関連付けのセットを通過する独自のclone_with_associationsメソッドを記述する必要があります。理論的にはcouldは、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
Max Williams

同様に、このgemはうまく機能しているようです: https://github.com/moiristo/deep_cloneable 、非常に使いやすいです。

ただ

gem ‘deep_cloneable’, ‘~> 1.4.0’

その後:

pirate.deep_clone :include => :mateys

16
Rob