Мой метод клонирования заключается в краже детей из оригинальной модели

Я проверил несколько вопросов по этому вопросу, в том числе здесь, здесь и здесь. Я не могу понять, что здесь происходит не так.

Вот мой метод копирования:

def copy(new_period)
  copy = self.dup
  copy.report_id = Report.maximum(:report_id).next
  copy.period_id = new_period
  copy.responses = self.responses.dup
  copy.save
end

Этот метод правильно делает копию модели отчета и назначает ее новому периоду, как и ожидалось. Он также перемещает всех детей из исходного отчета в новый отчет без дублирования, что не ожидается. Я не понимаю, почему это происходит.

У кого-нибудь есть идеи?

2 ответа

Решение

Я считаю, виновным является следующая строка

copy.responses = self.responses.dup

Возвращаемое значение из self.responses является ActiveRecord::Relation, Когда вы вызываете dup, вы дублируете экземпляр отношения, а не ресурсы, указанные областью действия.

Если вы хотите продублировать объекты ответа, вам сначала нужно их загрузить.

copy.responses = self.responses.map { |response| response.dup }

или же

copy.responses = self.responses.map(&:dup)

dup делает мелкую копию. Он также не копирует все свои дочерние объекты. Это важно отметить и с массивами и хэшами.

Решение состоит в том, чтобы написать метод клонирования для вашей модели:

def clone(new_period)
  copy = self.class.new self.attributes.slice(*%w{attributes to copy})
  copy.report_id = Report.maximum(:report_id).next
  copy.period_id = new_period
  copy.responses = Response.clone_multiple(self.responses)
  copy.save
end

Аналогично с ответом добавьте метод класса для клонирования коллекции:

class << self
  def clone_multiple(collection)
    collection.map do |response|
      copy = self.new(response.attributes.slice(*%w{attributes to clone})
      copy.save
      copy
    end
  end
end
Другие вопросы по тегам