【问题标题】:Symmetrical, self-referential HABTM relationship对称的、自我参照的 HABTM 关系
【发布时间】:2014-08-10 05:22:06
【问题描述】:


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

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

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

我尝试修改控制器的更新并创建操作以将两对 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 有点帮助,这似乎是一个棘手的案例,因为我有一个具有自引用关系的模型也是对称的。谢谢你的时间!

【问题讨论】:

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


    【解决方案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
    

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

    【讨论】:

    • 这要求我不要使用 has_and_belongs_to_many 关系,对吧?因为HABTM只使用没有相关模型的连接表?目前我没有 CoordinateImprintable 模型。
    • 是的,你必须做出改变,但这应该不会太难。我已将其添加到我的答案中。
    • 好吧,我花了一点时间,拉了几根头发,但我终于成功了!感谢您的帮助
    • 没问题!我很高兴为您服务!
    猜你喜欢
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-22
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多