0

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

@room1.north = @room2

@room2.south 会自动变成@room1。同样,如果我说:

@room1.east = nil

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

编辑

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
4

1 回答 1

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 关系。该模型可以保存有关方向的信息,并且可以更加灵活。例如,现在你不能创建一个有两个“北”入口的房间,也不能定义一个单向连接。有了它,您甚至可以找到特定的连接,并且可以随意更改它们。如果你想要更复杂的结构,比如这个简单的网格,那么考虑一下。

于 2012-07-15T20:33:43.783 回答