如何在保持原始ID和引用的同时,用另一条记录/行替换记录/行?

时间:2015-12-09 09:19:50

标签: ruby-on-rails activerecord updates

我有一个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”错误。

1 个答案:

答案 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或添加一个,或者订单以另一种方式更改,会发生什么情况)。