Подтвердить что ты не робот

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

Я .clone-запись записи в рельсах...

  new_blerg = Blerg.find(1).clone

В этой записи есть нагрузки и нагрузки ассоциаций, и эти ассоциации даже имеют ассоциации.

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

4b9b3361

Ответ 1

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

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

не забудьте проверить Amoeba Documentation, но использование довольно просто...

только

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 вы также можете добавить или запустить регулярное выражение в заданном поле

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

Ответ 2

Вам нужно написать собственный метод clone_with_associations, который проходит через определенный список ассоциаций. Теоретически вы могли бы написать что-то общее, которое использует reflection_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

Ответ 3

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

Просто

gem ‘deep_cloneable’, ‘~> 1.4.0’

а затем:

pirate.deep_clone :include => :mateys