I\'m currently cloning a single-level association like this:
class Survey < ActiveRecord::Base
def duplicate
new_template = self.clone
new_templ
Without using gems, you can do the following:
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
Then you can call:
new_survey = Survey.create
new_survey.copy_from(past_survey)
That will duplicate all questions from last Survey to new Survey and tie them.
You can also alias the rails dup method, as follows:
class Survey
has_many :questions, :inverse_of=>:survey, :autosave=>true
alias orig_dup dup
def dup
copy=orig_dup
copy.questions=questions
copy
end
end
class Questions
belongs_to :survey, :inverse_of=>:questions
has_many :answers, :inverse_of=>:question, :autosave=>true
alias orig_dup dup
def dup
copy=orig_dup
copy.answers=answers
copy
end
end
class Answer
belongs_to :question
end
and then you can do this
aaa = Survey.find(123).dup
aaa.save
You may also like the Amoeba gem for ActiveRecord 3.2.
In your case, you probably want to make use of the nullify
, regex
or prefix
options available in the configuration DSL.
It supports easy and automatic recursive duplication of has_one
, has_many
and has_and_belongs_to_many
associations, field preprocessing and a highly flexible and powerful configuration DSL that can be applied both to the model and on the fly.
be sure to check out the Amoeba Documentation but usage is pretty easy...
just
gem install amoeba
or add
gem 'amoeba'
to your Gemfile
then add the amoeba block to your model and run the dup
method as usual
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
You can also control which fields get copied in numerous ways, but for example, if you wanted to prevent comments from being duplicated but you wanted to maintain the same tags, you could do something like this:
class Post < ActiveRecord::Base
has_many :comments
has_and_belongs_to_many :tags
amoeba do
exclude_field :comments
end
end
You can also preprocess fields to help indicate uniqueness with both prefixes and suffixes as well as regexes. In addition, there are also numerous options so you can write in the most readable style for your purpose:
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
Recursive copying of associations is easy, just enable amoeba on child models as well
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
The configuration DSL has yet more options, so be sure to check out the documentation.
Enjoy! :)
Shouldn't it be..
new_question.answers << new_answer
end
new_template.questions << new_question
Use deep_clonable gem
new_survey = original_survey.clone :include => [:questions => :answers]