2011-12-22 43 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

相關問題