Клонирование записи в рельсах, возможно ли клонировать ассоциации и глубокое копирование?
Я клонирую запись в рельсах...
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