ActiveRecord: могу ли я копировать ассоциации?

17

Есть ли способ скопировать ассоциации одной модели в другую ...

template_model = MyModel.find(id)
new_model = template_model.clone
new_model.children << template_model.children # I want to *copy* children

... такое, что я копирую детей из шаблона в новую модель? (На самом деле этот код перемещает детей из шаблона в новую модель).

Я знаю, что я могу это сделать вручную, но есть ли более краткий путь?

Спасибо

    
задан Paul 27.03.2009 в 17:13
источник

4 ответа

25

Проблема в том, что вы клонируете шаблон, но не клонируете его. Попробуйте что-то вроде:

template_model = MyModel.find(id)
new_model = template_model.clone
new_model.children << template_model.children.collect { |child| child.clone }
    
ответ дан MarkusQ 27.03.2009 в 17:23
источник
  • Отлично! Вот и все - красиво и лаконично. Спасибо. –  Paul 27.03.2009 в 19:02
3

Добавьте это, где находится под / lib. Например clone_deep.rb.

module CloneDeep
  def clone_deep
    kopy = clone
    self.class.reflect_on_all_associations.each do |association|
      next if association.macro == :belongs_to
      cloned_object = case association.macro
                        when :has_many
                          self.send(association.name).collect { |item| item.clone_deep }
                        when :has_one
                          self.send(association.name) && self.send(association.name).clone_deep
                        else
                          clone
                      end
      kopy.send("#{association.name}=", cloned_object)
    end
    return kopy
  end
end

Создайте новый инициализатор в папке config / initializers /. Внутри этого файла вставьте

ActiveRecord::Base.send(:include, CloneDeep)

Теперь вы можете клонировать модель со всеми ее has_one и ассоциациями hos_many.

cloned_person = person.clone_deep
cloned_person.save
    
ответ дан Andrey Yasinishyn 18.10.2013 в 16:53
источник
  • Только это простое решение сработало для меня .. как amoeba, так и deep_cloneable gems по умолчанию вызывали dup и не копировали ассоциации .. deep_cloneable gem failed on has many through..rails 4.1 Thanks –  Abs 07.02.2016 в 01:33
1

#dup следует использовать вместо #clone , поскольку атрибуты не копируются в случае последнего.

module Promotion
  class Banner
    has_many :localizations
    has_many :images

    def deep_dup!
      duplicate = dup
      duplicate.save

      duplicate.localizations = localizations.collect { |localization| localization.dup }
      duplicate.images = images.collect { |image| image.dup }

      duplicate
    end
  end
end

Ссылка Ссылка

    
ответ дан Artur Beljajev 30.09.2015 в 01:53
источник
0

Ну, это не совсем копия.

Но вы могли бы сделать

new_model.child_ids = template_model.child_ids
    
ответ дан Jimmy Stenke 27.03.2009 в 17:23
источник