私は現在、次のような単一レベルの関連付けを複製しています。
class Survey < ActiveRecord::Base
def duplicate
new_template = self.clone
new_template.questions << self.questions.collect { |question| question.clone }
new_template.save
end
end
そのため、Survey
のクローンを作成してから、その調査に関連付けられたQuestions
のクローンを作成します。結構です。それは非常にうまく機能します。
しかし、私が問題を抱えているのは、それぞれの質問がhas_many
Answers
。そう Survey has_many Questions which has_many Answers
。
答えを正しく複製する方法がわかりません。私はこれを試しました:
def duplicate
new_template = self.clone
self.questions.each do |question|
new_question = question.clone
new_question.save
question.answers.each do |answer|
new_answer = answer.clone
new_answer.save
new_question.answers << answer
end
new_template.questions << question
end
new_template.save
end
しかし、それは実際に元の回答を置き換えてから新しい回答を作成するという奇妙なことをするので、IDは正しく一致しなくなります。
new_survey = original_survey.clone :include => [:questions => :answers]
ActiveRecord 3.2の Amoeba gem もお勧めです。
あなたの場合、おそらく構成DSLで利用可能なnullify
、regex
、またはprefix
オプションを利用したいと思うでしょう。
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
どのフィールドをさまざまな方法でコピーするかを制御することもできますが、たとえば、コメントが重複しないようにしたいが、同じタグを維持したい場合は、次のようにすることができます。
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
include_field :tags
prepend :title => "Copy of "
append :contents => " (copied version)"
regex :contents => {:replace => /dog/, :with => "cat"}
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
構成DSLにはさらに多くのオプションがあるため、必ずドキュメントを確認してください。
楽しい! :)
gemを使用せずに、次のことができます:
class Survey < ApplicationRecord
has_and_belongs_to_many :questions
def copy_from(last_survey)
last_survery.questions.each do |question|
new_question = question.dup
new_question.save
questions << new_question
end
save
end
…
end
次に、電話をかけることができます:
new_survey = Survey.create
new_survey.copy_from(past_survey)
これにより、前回の調査から新しい調査までのすべての質問が複製され、それらが関連付けられます。
そうではないはずです。
new_question.answers << new_answer
end
new_template.questions << new_question