我的Match
模型有3
个用户:observer
,player1
,player2
和status
枚举(可以是finished
或pending
)。
当Match
为finished
时,我希望能够访问匹配的winner
(可以是player1
或player2
) ,以及loser
。
我知道实现这一点的最简单方法是存储5个用户引用,但这听起来并不好。
另一种方法是在模型中自己实现winner, loser, winner=, loser=
等方法,但这就是ActiveRecord的用途......
有什么建议吗?
当前代码:
class Match < ApplicationRecord
validates :observer, :player1, :player2, :status, presence: true
belongs_to :observer, class_name: 'User', foreign_key: 'observer_id'
belongs_to :player1, class_name: 'User', foreign_key: 'player1_id'
belongs_to :player2, class_name: 'User', foreign_key: 'player2_id'
enum status: [:pending, :finished]
end
E:我的问题不在于如何实现这一点,我知道一些方法,我的问题是以一种我不知道手动挂钩的方式实现这一点(即编写访问器winner,loser
等。
答案 0 :(得分:0)
我建议在这里有两个型号。一个用于Match
&amp; User
。两者都具有状态列,并且匹配的关联具有许多用户。当Match
从pending
更改为finished
州时,请将User
状态从playing
更改为winner
或looser
。通过这种方式,您可以轻松查询获胜者和放松者。
答案 1 :(得分:0)
无论如何,在某个地方,你必须存储胜利者是谁。然而,由于比赛中只有两名球员,所以好消息是你不需要存储输家,因为它总是只是一个不是赢家的球员。
您可以通过以下几种方式实现此目标:
让winner
列(格式化为字符串)指定赢得者的关联,即"player1"
或"player2"
。然后你可以创建一个winner()
方法来覆盖属性的返回值(给你实际的User
对象),如下所示:
def winner
send(read_attribute(:winner))
end
然后,您的loser()
方法可能如下所示:
def loser
player1 == winner ? player2 : player1
end
使用这种方法,您不必声明其他关联,但权衡是一些混乱:
winner
字段的值可能很尴尬,容易出现人为错误(即错别字)。player_one
和player_two
,则整个除非您也更新数据,否则会中断。User
对象以确定哪一个是失败者。对我而言,实现这一目标的最干净,最“Railsy”的方法就是简单地使用winner_id
列。这会给你一个额外的联想:
belongs_to :winner, class_name: 'User', foreign_key: 'winner_id'
这看似多余,但它可以让你做一些事情:
您只需执行@match.winner = @match.player1
或@match.winner = @match.player2
即可分配获胜者。
您可以通过以下方式轻松找到失败者:
def loser
winner_id == player1_id ? player2 : player1
end
哪个不要求实例化两个玩家User
对象以返回失败者。
您可以进行合理/可测试的数据验证:
validate :winner_is_player_in_match
private
def winner_is_player_in_match
unless [player1_id, player2_id].include?(winner_id)
errors.add(:winner, 'must be one of the players in the match.')
end
end