对称的,自我指涉的HABTM关系

时间:2014-06-19 15:33:35

标签: ruby-on-rails associations has-and-belongs-to-many


在我的架构中,我有一个名为Imprintables的模型。在这个模型中,我有这种自我指涉关系:

class Imprintable < ActiveRecord::Base
  has_and_belongs_to_many :coordinates, class_name: 'Imprintable', association_foreign_key: 'coordinate_id', join_table: 'coordinates_imprintables'
...
end

在可打印的创建/编辑表单中,我有一个选择字段,用户可以在其中选择坐标imprintables(坐标用于标识与正在创建/编辑的imprintables类似的imprintables)。我的问题是,如果我有一个可以打印的A和可打印的B,当我创建A并将列表B作为一个可以打印的坐标时,我希望能够查看B的编辑表单并查看A也列为坐标。 / p>

我尝试修改控制器的更新并创建操作以将两对id插入到链接器表(coordinates_imprintables)中。例如,如果A.id = 1且B.id = 2,则执行一些sql,如:

INSERT INTO coordinates_imprintables (imprintable_id, coordinate_id) VALUES (1, 2)
INSERT INTO coordinates_imprintables (imprintable_id, coordinate_id) VALUES (2, 1)

但我无法让它工作,因为我不知道如何知道用户何时尝试删除或插入坐标,我甚至不确定这是否是正确的答案。 Railscasts略有帮助,这似乎是一个棘手的案例,因为我有一个具有自我指涉关系的模型也是对称的。谢谢你的时间!

1 个答案:

答案 0 :(得分:1)

您在这里寻找的是model callbacks。它们在对象生命周期中的操作之前,之后或期间执行。

为了在您的情况下使用这些,您可以为CoordinatedImprintable表添加模型。然后,无论何时创建,更新或销毁coordinate_imprintable,您都需要为其镜像执行相同的操作。

class CoordinateImprintable < ActiveRecord::Base
  belongs_to :imprintable
  belongs_to :coordinate, class_name: 'Imprintable', foreign_key 'imprintable_id'
  after_create :add_mirror
  after_update :update_mirror
  after_destroy :destroy_mirror

  def add_mirror
    self.class.find_or_create(imprintable: coordinate, coordinate: imprintable)
  end

  def update_mirror
    if self.changed?
      mirror = self.class.find(imprintable: coordinate_was, coordinate: imprintable_was)
      mirror.update_attributes(imprintable: coordinate, coordinate: imprintable)
    end
  end

  def destroy_mirror
    mirror = self.class.find(imprintable: coordinate, coordinate: imprintable)
    mirror.destroy if mirror && !mirror.destroyed
  end
end

您还需要将has_and_belongs_to_many关系更改为两个has_many :through关系。

class Imprintable
  has_many :coordinate_imprintables
  has_many :coordinate, through: :coordinate_imprintables
  has_many :mirrored_coordinate_imprintables, class_name: 'CoordinateImprintable', foreign_key: 'coordinate_id'
  has_many :mirrored_coordinates, through: :mirrored_coordinate_imprintables, source: :imprintable
end

希望这有帮助!如有任何问题,请随时发表评论。