根据状态更改模型属性名称?

时间:2017-02-12 03:54:11

标签: ruby-on-rails rails-activerecord

我的Match模型有3个用户:observerplayer1player2status枚举(可以是finishedpending)。

Matchfinished时,我希望能够访问匹配的winner(可以是player1player2) ,以及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等。

2 个答案:

答案 0 :(得分:0)

我建议在这里有两个型号。一个用于Match&amp; User。两者都具有状态列,并且匹配的关联具有许多用户。当Matchpending更改为finished州时,请将User状态从playing更改为winnerlooser。通过这种方式,您可以轻松查询获胜者和放松者。

答案 1 :(得分:0)

无论如何,在某个地方,你必须存储胜利者是谁。然而,由于比赛中只有两名球员,所以好消息是你不需要存储输家,因为它总是只是一个不是赢家的球员。

您可以通过以下几种方式实现此目标:

1。

winner列(格式化为字符串)指定赢得者的关联,即"player1""player2"。然后你可以创建一个winner()方法来覆盖属性的返回值(给你实际的User对象),如下所示:

def winner
  send(read_attribute(:winner))
end

然后,您的loser()方法可能如下所示:

def loser
  player1 == winner ? player2 : player1
end

使用这种方法,您不必声明其他关联,但权衡是一些混乱:

  1. 分配winner字段的值可能很尴尬,容易出现人为错误(即错别字)。
  2. 这是危险的,因为您存储字符串值以表示可能更改的关联的名称 - 即,如果您决定将关联的名称更改为player_oneplayer_two,则整个除非您也更新数据,否则会中断。
  3. 确定失败者需要实例化player1 player2 User对象以确定哪一个是失败者。
  4. 2

    对我而言,实现这一目标的最干净,最“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