我有一个ActiveRecord对象,其中包含3个“has_many”关系/ sub ActiveRecords。
我的目标是让“克隆”能够修改自己版本的og_actions / og_objects / ob_stories用于测试目的,但也能够将数据从父级推送到所有克隆以覆盖任何更改做了。
我假设这样做的方法是使用另一个ActiveRecord中的数据更新这些关系,但是,当我复制数据时,我不想更改ID或Foreign_key引用。
我如何以惯用的方式做到这一点? 或者我应该删除所有记录并使用旧ID创建新记录?如果是这样,最好的办法是什么?
以下是我正在使用的代码,它不起作用:
class App < ActiveRecord::Base
...
belongs_to :user
has_many :og_actions
has_many :og_objects
has_many :og_stories
has_many :log_reports
has_many :clones, class_name: "App", foreign_key: "parent_id"
...
def populate_clones
self.clones.each do |c|
p "updating ->"
self.og_actions.each_with_index do | oa, ai |
new_og_action = OgAction.create(oa.attributes.merge({app_id:c.id, id: c.og_actions[ai].id }))
c.og_actions[ai] = new_og_action
end
self.og_objects.each_with_index do |oo, oi|
new_og_object = OgObject.create(oo.attributes.merge({app_id:c.id, id: c.og_objects[oi].id }))
c.og_objects[oi] = new_og_object
end
self.og_stories.each_with_index do | s, si|
new_og_story = OgStory.create(s.attributes.merge({app_id:c.id, id: c.og_stories[si].id }))
s.story_variants.each do_with_index do |v, vi|
new_variant = StoryVariant.create(v.attributes.merge({og_story_id:new_og_story.id, id:c.og_stories[si].story_variants[vi].id}))
new_og_story.story_variants[vi] = new_variant
end
c.og_stories[si] = new_og_story
end
c.save
end
p "end Update"
end
我也尝试过使用replace函数,以及c.og_objects = self.og_objects的简单赋值似乎没有什么工作正常。它创建一个创建重复的新记录,替换所有引用,因此父ActiveRecord丢失其引用,或者获得“重复ID”错误。
答案 0 :(得分:1)
这很棘手。我一直在思考越来越多可能存在问题的案例。无论如何这是一个开始:
def sync_clones
clones.each do |clone|
# Destroy any og_actions for clone that are no longer in the parent app
clone.og_actions.where.not(parent_id: og_actions.ids).destroy_all
# Create or update a og_action clone for app clone
og_actions.each do |og_action|
clone_attributes = og_action.dup.attributes.except("id").merge(parent_id: og_action.id)
existing = clone.og_actions.find_by(parent_id: og_action.id)
if existing
existing.update(clone_attributes)
else
clone.og_actions.build(clone_attributes)
end
end
# ...
end
end
这将忠实地更新克隆,而不是创建不必要的记录。它确实需要您跟踪父og_action记录。这是因为您不能依赖og_actions
索引来识别匹配的克隆记录(如果您销毁一个og_action
或添加一个,或者订单以另一种方式更改,会发生什么情况)。