[英]ActiveRecord: How can I clone nested associations?
I'm currently cloning a single-level association like this:我目前正在克隆这样的单级关联:
class Survey < ActiveRecord::Base
def duplicate
new_template = self.clone
new_template.questions << self.questions.collect { |question| question.clone }
new_template.save
end
end
So that clones the Survey
then clones the Questions
associated with that survey.因此,克隆
Survey
然后克隆与该调查相关的Questions
。 Fine.美好的。 That works quite well.
这工作得很好。
But what I'm having trouble with is that each question has_many
Answers
.但我遇到的问题是每个问题
has_many
Answers
。 So Survey has_many Questions which has_many Answers
.所以
Survey has_many Questions which has_many Answers
。
I can't figure out how to clone the answers properly.我不知道如何正确克隆答案。 I've tried this:
我试过这个:
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
But that does some weird stuff with actually replacing the original answers then creating new ones, so ID's stop matching correctly.但这确实会发生一些奇怪的事情,即实际替换原始答案然后创建新答案,因此 ID 停止正确匹配。
Use deep_clonable gem使用deep_clonable gem
new_survey = original_survey.clone :include => [:questions => :answers]
You may also like the Amoeba gem for ActiveRecord 3.2.您可能还喜欢 ActiveRecord 3.2 的Amoeba gem 。
In your case, you probably want to make use of the nullify
, regex
or prefix
options available in the configuration DSL.在您的情况下,您可能希望使用配置 DSL 中可用的
nullify
、 regex
或prefix
选项。
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.它支持简单且自动的
has_one
、 has_many
和has_and_belongs_to_many
关联的递归复制、字段预处理和高度灵活且功能强大的配置 DSL,可同时应用于 model 和运行中。
be sure to check out the Amoeba Documentation but usage is pretty easy...请务必查看Amoeba 文档,但使用起来非常简单......
just只是
gem install amoeba
or add或添加
gem 'amoeba'
to your Gemfile到您的 Gemfile
then add the amoeba block to your model and run the dup
method as usual然后将变形虫块添加到您的 model 并像往常一样运行
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
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.配置 DSL 有更多选项,因此请务必查看文档。
Enjoy: :)享受: :)
Without using gems, you can do the following:在不使用 gems 的情况下,您可以执行以下操作:
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.这会将上次调查中的所有问题复制到新调查中并将它们联系起来。
Shouldn't it be..不应该吗。。
new_question.answers << new_answer
end
new_template.questions << new_question
You can also alias the rails dup method, as follows:您还可以为 rails dup 方法设置别名,如下所示:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.