You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Amoeba Gem克隆Rails模型时的PageElementDependency关联异常

Fixing Bidirectional Association Cloning with Amoeba in Rails

Hey there, I’ve run into this exact issue with Amoeba when cloning models with bidirectional self-associations—default cloning logic doesn’t handle the cross-references between cloned records correctly. Let’s break down how to fix this.

The Root Problem

When you clone your Page, Amoeba creates new PageElement records, but it doesn’t automatically map both sides of the PageElementDependency association to their cloned counterparts. It only updates one ID (like the dependee_id) while leaving the other (dependent_id) pointing to the original record.

Solution: Use Amoeba’s Remapper to Map Cloned Records

Amoeba provides a remapper hash that tracks original objects to their cloned versions. We can use this in a custom lambda to manually update both sides of the dependency association after cloning.

Here’s the revised code for your models:

1. Page Model (No Changes Needed)

# models/page.rb
has_many :page_elements, -> { order(position: :asc) }, inverse_of: :page, dependent: :destroy
amoeba do
  enable clone [:page_elements]
end

2. PageElement Model (Updated Amoeba Configuration)

This is where the magic happens—we add a custom customize block to fix the dependency IDs:

# models/page_element.rb
has_many :dependent_page_element_dependencies, foreign_key: :dependent_id, inverse_of: :dependent, class_name: "PageElementDependency", dependent: :destroy
has_many :dependees, through: :dependent_page_element_dependencies
has_many :dependee_page_element_dependencies, foreign_key: :dependee_id, inverse_of: :dependee, class_name: "PageElementDependency", dependent: :destroy
has_many :dependents, through: :dependee_page_element_dependencies

amoeba do
  enable clone [:dependee_page_element_dependencies, :dependent_page_element_dependencies]
  
  # Custom logic to map both sides of the dependency to cloned records
  customize(lambda { |original_element, cloned_element|
    # Fix dependencies where this element is the dependent (it relies on another element)
    cloned_element.dependent_page_element_dependencies.each do |cloned_dep|
      original_dependee = original_element.dependees.find_by(id: cloned_dep.dependee_id)
      if original_dependee
        # Grab the cloned version of the original dependee from Amoeba's remapper
        cloned_dependee = amoeba.remapper[original_dependee]
        cloned_dep.update(dependee_id: cloned_dependee.id) if cloned_dependee
      end
    end

    # Fix dependencies where this element is the dependee (another element relies on it)
    cloned_element.dependee_page_element_dependencies.each do |cloned_dep|
      original_dependent = original_element.dependents.find_by(id: cloned_dep.dependent_id)
      if original_dependent
        cloned_dependent = amoeba.remapper[original_dependent]
        cloned_dep.update(dependent_id: cloned_dependent.id) if cloned_dependent
      end
    end
  })
end

3. PageElementDependency Model (No Changes Needed)

# models/page_element_dependency.rb
belongs_to :dependent, class_name: "PageElement", inverse_of: :dependent_page_element_dependencies, foreign_key: :dependent_id
belongs_to :dependee, class_name: "PageElement", inverse_of: :dependee_page_element_dependencies, foreign_key: :dependee_id

How This Works

  • The remapper stores every original object as a key, with its cloned counterpart as the value. This is populated as Amoeba clones each record in the association tree.
  • In the customize block, we loop through both sets of dependencies on the cloned PageElement:
    • For each dependency, we find the original associated PageElement.
    • We then look up its cloned version in the remapper and update the dependency record’s ID to point to the cloned element.

Testing the Fix

When you clone Page#3 (with PageElement#4 and #5 linked by a dependency), you’ll now get:

  • A new Page with PageElement#6 and #7
  • A PageElementDependency where dependent_id = 6 and dependee_id = 7 (both pointing to the cloned elements)

内容的提问来源于stack exchange,提问作者Waclock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:58:00