Клонирование записи в рельсах, возможно ли клонировать ассоциации и глубокое копирование?

Я клонирую запись в рельсах...

  new_blerg = Blerg.find(1).clone

Эта запись имеет множество и множество ассоциаций, и эти ассоциации даже имеют ассоциации.

Есть ли способ глубокого копирования записи и ее клонирования, чтобы она также была клонирована со всеми этими ассоциациями?

3 ответа

Решение

Вы можете получить хорошее использование драгоценного камня Amoeba для ActiveRecord 3.2.

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

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

просто

gem install amoeba

или добавить

gem 'amoeba'

в ваш Gemfile

затем добавьте блок амебы к вашей модели и запустите 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

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

class Post < ActiveRecord::Base
  has_many :comments
  has_and_belongs_to_many :tags

  amoeba do
    include_field :comments
  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
    recognize :has_and_belongs_to_many
  end
end

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

Amoeba также автоматически вернется к дочерним записям, если вы их включите

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

Вы также можете добавить в поля дополнительные данные, чтобы указать уникальность

class Post < ActiveRecord::Base
  has_many :comments

  amoeba do
    enable
    prepend :title => "Copy of "
  end
end

и в дополнение к prepend вы также можете добавить или запустить регулярное выражение в данном поле

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

Вам нужно написать свой собственный метод clone_with_associations, который проходит через определенный список ассоциаций. Теоретически вы могли бы написать что-то общее, использующее отражать_on_all_associations, но вам нужно было бы сделать то же самое для связанных объектов, и это неизбежно привело бы к созданию цикла, который генерирует бесконечное количество записей.

Так что, просто напишите свое. Что-то вроде

  #in Blerg
  has_many :foos
  has_many :bars #bars also have many chickens which we want to copy over as well
  def clone_with_associations
    new_blerg = self.dup
    new_blerg.save
    #simple association
    new_blerg.foos = self.foos
    #two-level association 
    self.bars.each do |bar|
      new_bar = bar.clone
      new_bar.save
      new_bar.chickens = bar.chickens 
      new_blerg.bars << bar
    end
    new_blerg
  end

Теперь вы можете сделать

@new_blerg = Blerg.find(1).clone_with_associations

Точно так же этот драгоценный камень, кажется, работает хорошо: https://github.com/moiristo/deep_cloneable и довольно прост в использовании.

Просто

gem ‘deep_cloneable’, ‘~> 1.4.0’

а потом:

pirate.deep_clone :include => :mateys

Другие вопросы по тегам