2011-12-22 59 views
1

我有一个items表,我需要创建一些不同的对。我的模式包含一个equivalent_id,它存储伙伴的ID,如果该伙伴存在。在同一模型中设置一对记录的关系

在模型中建立关系的最佳方法是什么?看起来很奇怪的是has_onebelongs_to,因为这两个对中的任何一个都没有任何概念上的优势。

回答

1

使用has_one,你可以说has_one :equivalent, :class_name => "Item"它看起来对我来说是可读的。

1

一对一的自我指涉和双向关联(令人惊讶的是)更复杂一对多甚至多对多的自我指涉和双向关联。

只是要清楚:

  • 自我指涉:相关产品相同的类,它的主人的一个实例。
  • 双向:如果一个项目是另一个项目的等价物,那么后者也相当于首先提到的。

这意味着:

revolver = Item.create name: 'revolver' 
pistol = Item.create name: 'pistol' 

revolver.equivalent = pistol 
revolver.equivalent # => pistol 
pistol.equivalent # => revolver 

换句话说,当你设置equivalent_id一个项目,业主equivalent_id也必须设置。

One-to-One关联不接受insert_sqldelete_sql选项。所以它不太漂亮。然而,要做到这一点(IMO)最干净的方法是:

class Item < ActiveRecord::Base 
    has_one :equivalent, class_name: 'Item', foreign_key: 'equivalent_id' 

    def add_equivalent(other) 
    self.equivalent = other 
    other.equivalent = self 
    end 

    def remove_equivalent 
    equivalent.equivalent = nil 
    self.equivalent  = nil 
    end 
end 

这种方式,你可以这样做:

revolver = Item.create name: 'revolver' 
pistol = Item.create name: 'pistol' 

revolver.add_equivalent(pistol) 
revolver.equivalent # => pistol 
pistol.equivalent # => revolver 

pistol.remove_equivalent 
pistol.equivalent # => nil 
revolver.equivalent # => nil 

编辑

是安全的,应该清理一下每次添加等价物时的关系。这意味着:

revolver.equivalent # => pistol 
pistol.equivalent # => revolver 

revolver.add_equivalent(gun) 
revolver.equivalent # => gun 
pistol.equivalent # => nil 

你可以做这样的:

def add_equivalent(other) 
    remove_equivalent if equivalent 
    ... 
end 
+0

您可以覆盖当量=替换任何现有的等价物。假设只能有一个。 – rkb 2011-12-22 19:41:25

+0

@rkb如果那么简单,我会很开心。我在答案中跳过了细节,但可以随意尝试发布。我肯定会为更好的答案投票。事务有时是反复无常的(特别是在创建新关系之前清除现有关系)。再次,我认为这是**最干净的方式。 – Damien 2011-12-22 20:54:51

相关问题