我有一个items
表,我需要创建一些不同的对。我的模式包含一个equivalent_id
,它存储伙伴的ID,如果该伙伴存在。在同一模型中设置一对记录的关系
在模型中建立关系的最佳方法是什么?看起来很奇怪的是has_one
或belongs_to
,因为这两个对中的任何一个都没有任何概念上的优势。
我有一个items
表,我需要创建一些不同的对。我的模式包含一个equivalent_id
,它存储伙伴的ID,如果该伙伴存在。在同一模型中设置一对记录的关系
在模型中建立关系的最佳方法是什么?看起来很奇怪的是has_one
或belongs_to
,因为这两个对中的任何一个都没有任何概念上的优势。
使用has_one
,你可以说has_one :equivalent, :class_name => "Item"
它看起来对我来说是可读的。
一对一的自我指涉和双向关联(令人惊讶的是)更复杂一对多甚至多对多的自我指涉和双向关联。
只是要清楚:
这意味着:
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_sql
和delete_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
您可以覆盖当量=替换任何现有的等价物。假设只能有一个。 – rkb 2011-12-22 19:41:25
@rkb如果那么简单,我会很开心。我在答案中跳过了细节,但可以随意尝试发布。我肯定会为更好的答案投票。事务有时是反复无常的(特别是在创建新关系之前清除现有关系)。再次,我认为这是**最干净的方式。 – Damien 2011-12-22 20:54:51