Rails 3:与自身具有多个双向关系的模型

时间:2012-07-15 20:18:35

标签: ruby-on-rails-3 model associations self-join bidirectional-relation

我正在尝试在Rails 3中构建一个文本冒险游戏(是的,我知道这很愚蠢)。现在我有一个名为Room的模型。每个房间最多需要与其他四个房间相关联。这种关系是双向的,这样任何两个相关的房间都会相互出口。例如,如果我要说:

@room1.north = @room2

@ room2.south将自动成为@ room1。同样,如果我要说:

@room1.east = nil

@ room2.west也变成了零。我想仅使用模型关联来实现这一点,而不是在控制器中手动执行。这可能吗?

修改

matzi给出的第一个例子并不像我想要的那样完成。请考虑以下事项:

class Room < ActiveRecord::Base
  attr_accessible :north, :south, :east, :west

  has_one :north, :class_name => "Room", :foreign_key => "south_id"
  has_one :east, :class_name => "Room", :foreign_key => "west_id"

  belongs_to :south, :class_name => "Room", :foreign_key => "south_id"
  belongs_to :west, :class_name => "Room", :foreign_key => "west_id"
end

@room1 = Room.new
@room2 = Room.new
@room1.save
@room2.save

这很好用:

@room1.north = @room2

@room1.north #Outputs @room2
@room2.south #Outputs @room1

@room1.north = nil

@room1.north #Outputs nil
@room2.south #Outputs nil

到目前为止一切顺利。但是:

@room1.north = @room2

@room2.south = nil

@room1.north #Outputs @room2, but it should be nil
@room2.south #Outputs nil

此外:

@room2.south = @room1

@room1.north #Outputs nil, but it should be @room2
@room2.south #Outputs @room1

在这里查看问题?这不是真正的双向。

解决

事实证明,Matzi的第一个解决方案毕竟是正确的。正如他所指出的那样,我对该解决方案的问题是节约。以下作品:

@room1 = Room.create
@room2 = Room.create
@room1.north = @room2
@room1.save

Room.find(1).north #Room 2
Room.find(2).south #Room 1

@room2.south = nil
@room2.save

Room.find(1).north #nil
Room.find(2).south #nil

1 个答案:

答案 0 :(得分:0)

当然有可能。选择保存id(north_id和east_id)的两个方向(例如北和东),因为不需要全部四个。然后通过:foreign_key设置关系。注意id的,因为has_one标记了另一方的id名称,而belongs_to标记了同一对象中的id。

应该有效:

has_one :south, :class_name => 'Room', :foreign_key => 'north_id'
belongs_to :north, :class_name => 'Room', :foreign_key => 'north_id'

但是我建议您使用连接器模型和HABTM实现。该模型可以保存有关方向的信息,并且可以更加灵活。例如。现在你不能创建一个有两个“北”入口的房间,也不能定义一个单向连接。有了它,您甚至可以找到特定的连接,您可以随意更改它们。如果你想要更复杂的结构,比如这个简单的网格,那就考虑一下。