ActiveRecord: Как я могу клонировать вложенные ассоциации?

В настоящее время я клонирую одноуровневую ассоциацию, подобную этой:

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, 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 перестает правильно соответствовать.

25
задан Shpigford 15 July 2011 в 19:03
поделиться

2 ответа

Вам также может понравиться камень Amoeba для ActiveRecord 3.2.

В вашем случае вы, вероятно, захотите использовать опции nullify, regex или prefix, доступные в конфигурации DSL.

Он поддерживает простое и автоматическое рекурсивное дублирование ассоциаций has_one, has_many и has_and_belongs_to_many, предварительную обработку поля и очень гибкую и мощную конфигурацию DSL, которая может применяться как к модели, так и на лету.

Обязательно ознакомьтесь с Документацией Amoeba , но использовать ее довольно просто ...

просто

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

Вы также можете контролировать, какие поля копируются различными способами, но, например, если вы хотите предотвратить дублирование комментариев, но хотите сохранить те же теги, вы можете сделать что-то вроде этого:

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 есть еще больше опций, поэтому обязательно ознакомьтесь с документацией.

Наслаждайтесь! :)

3
ответ дан 28 November 2019 в 20:57
поделиться

Не должно ли быть ..

  new_question.answers << new_answer
end

new_template.questions << new_question
0
ответ дан 28 November 2019 в 20:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: