【问题标题】:Ruby on Rails: Use Association For Two Fields?Ruby on Rails:对两个字段使用关联?
【发布时间】:2019-12-01 23:55:37
【问题描述】:

我的 Rails 应用程序中目前有两个模型:TeamPlayer,如下所示:

class Team < ApplicationRecord
  has_many :players
end

class Player < ApplicationRecord
  belongs_to :team
end

我想添加一个Matchup 类来代表两支球队互相比赛。在正常的 OOP 领域中,我可能会执行以下操作:

class Matchup
  attr_accessor :first_team, :second_team
end

但我不能 100% 确定 Rails 惯用的设置方式是什么。我正在考虑的一些选项:

1) 使用关联:Matchup 有许多球队,Team 属于许多对战。这有点尴尬,因为现在我无法为first_teamsecond_team 分别指定一个字段。

2) 坚持 OOP 方法。 Matchup 有两个字段:first_teamsecond_team,均指代 Team 对象。由于我主要计划允许用户查看比赛,因此我不需要在此处使用资源路由。

提前感谢您提供的任何帮助!

【问题讨论】:

  • 我倾向于使用关联方法。它更灵活,因为您永远不知道比赛何时可能超过 2 支球队或循环赛等。如果您采用 OOP 方式,我建议团队可能是一个数组。

标签: ruby-on-rails ruby activerecord


【解决方案1】:

一场比赛可能属于两支球队。您可以指定不同的关联名称,然后告诉它要使用的类。

belongs_to :team_a, class_name: "Team"
belongs_to :team_b, class_name: "Team"

然后一个团队有很多对决,这也是有道理的。

【讨论】:

  • 不幸的是,您不能只创建一个 has_many 关联,因为团队可以在任一外键中。您必须执行这个尴尬的WHERE team_a = :x OR team_b = :x 查询或创建两个单独的关联并将它们与+ 连接在一起。
【解决方案2】:

在对战表上放置两个外键列似乎是最简单的解决方案,但问题在于细节。由于您有两个外键,您不能只创建一个has_many :matchups 关联,因为Rails 无法知道匹配中的哪一列对应于teams.id。所以这会导致非常尴尬的黑客攻击,例如:

class Team
  has_many :matchups_as_a, class_name: "Matchup"
                           foreign_key: 'team_a'
  has_many :matchups_as_b, class_name: "Matchup"
                           foreign_key: 'team_b'
  def matchups
     matchups_as_a + matchups_as_b
  end
end

这会破坏排序和许多其他事情。

或者:

Matchup.where('team_a = :x OR team_b = :x', x: team)

这不是一个关联,例如不能预先加载。

另一种方法是创建一个连接表:

class Matchup
  has_many :matchup_teams
  has_many :teams, though: :matchup_teams
end

# rails g model MatchupTeam match_up:references team:references
class MatchupTeam
  belongs_to :match_up
  belongs_to :team
end

class Team
  has_many :matchup_teams
  has_many :matchups, through: :matchup_teams
end

这可能看起来更复杂,但实际上可以让您这样做:

team.matchups
matchup.teams

# Get matchups between team and other_team
matches = Matchups.joins(:teams)
           .where(teams: { id: [team, other_team] })
           .group('matchups.id')
           .having('count(*) = 2')

【讨论】:

    猜你喜欢
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多