如何在维护原始id和引用的同时,用另一条记录/行惯用地替换一条记录或行



我有一个ActiveRecord对象,它有3个"has_many"关系/子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"错误。

这很棘手。我一直在思考越来越多可能存在问题的案例。无论如何,这里是一个开始:

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或添加一个,或者以其他方式更改顺序,会发生什么情况)。

最新更新