has_and_belongs_to_many关联的排序

10
在我的Rails应用程序中,我有两个模型通过has_and_belongs_to_many关联。这意味着有一个联接表。
想象一下,我要将用户添加到游戏中的情况。如果我想要添加一个用户,我会执行以下操作:
@game.users << @user

假设我想知道我添加这些用户的顺序,可以这样做:

@game.users.each do....

我的问题是:

  1. 这个列表的顺序保证每次读起来都相同吗?

  2. 如果是这样的话,有什么干净的方式可以重新排列游戏中的用户?


has_and_belongs_to_many :users, -> { order('users.id ASC') } - Constantin De La Roche
2个回答

20

要进一步解释danivo的答案:

如果你想按照它们添加到此列表的时间顺序进行排序,那么我建议您不要使用has_and_belongs_to_many,而是实际上使用has_many:through

game.rb

has_many :played_games
has_many :users, :through => :played_games, :order => "played_games.created_at ASC"

user.rb

has_many :played_games
has_many :games, :through => :played_games

played_game.rb

belongs_to :game
belongs_to :user

当然,名称可能会更改...

如果played_games表中有一个名为created_at的列,那么游戏中的第二个has_many将按照这个字段排序,并按照用户添加到游戏中的顺序返回用户。


我认为这对我有用...为了提供更多背景信息 - 我不需要按用户名排序,而是希望服务器随机选择一个顺序,以便通过它来决定游戏中的玩家位置。所以我想我可以在played_game表中放置一个“player_index”字段,并在我想要决定谁先移动时提供索引... - cmaughan

12

我不确定,但我认为如果没有order by子句,订单应该与数据库保证结果集的顺序相同。

您可以在:has_and_belongs_to_many关系语句中添加:order => "last_name, first_name asc"。这将设置返回项目顺序的默认行为。

您也可以执行@game.users.find(:all, :order => "last_name, first_name asc")或创建用于常见排序的命名范围。 查看详细信息的API

如果知道添加它们的顺序真的很重要,则可能需要切换到has_many :through关系,以便联接表具有自身的实体。 然后,Rails将管理该关系的created_onupdated_on时间戳。


1
SQL标准明确不涉及排序。通常情况下,记录被选取时会按照创建顺序排列,因为这是在组装结果集时的一种偶然性。一个经历了许多更新的数据库可能会有记录散布在各处。如果用户需要考虑顺序,就可以指定排序方式。我在使用Rails时曾因#last在Postgres上返回不同结果而受到伤害。 - Ghoti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接