繁体   English   中英

Rails has_many 通过 HABTM 关系

[英]Rails has_many through a HABTM relationship

所以我有三个模型,用户、团队和游戏。 目前是这样建造的。

class Team < ApplicationRecord
    has_and_belongs_to_many :users
    has_many :home_games, class_name: 'Game', foreign_key: 'home_team_id'
    has_many :away_games, class_name: 'Game', foreign_key: 'away_team_id'
    has_many :wins, class_name: 'Game', foreign_key: 'winner_id'
    belongs_to :owner, class_name: 'User'
end
class User < ApplicationRecord
  has_and_belongs_to_many :teams
  has_many :teams_owned, class_name: 'Team', foreign_key: 'owner_id'
  has_many :games, through: :teams
end
class Game < ApplicationRecord
  belongs_to :home_team, class_name: "Team"
  belongs_to :away_team, class_name: "Team"
  belongs_to :winner, class_name: "Team", optional: true
end

我想在用户和游戏之间添加关联。 所以我可以调用 User.games 和 Game.users。

我尝试添加这个:

#in user model
has_many :games, through: :teams

#in team model
has_many :games, ->(team) { where('home_team_id = ? or away_team_id = ?', team.id, team.id) }, class_name: 'Game'

正如api 文档所说的那样。 但是,当我尝试调用此关联时,出现“game.team_id 不存在”的错误。 由于每场比赛都有 home_team_id 和 away_team_id,但没有 team_id。

我只是执行得非常糟糕吗? 或者我错过了什么? 任何帮助表示赞赏。

我会说这不是一个很好的解决方案。

在 ActiveRecord 中,您实际上无法定义外键可能位于两个不同列中的关联,如下所示:

has_many :games, ->(team) { where('home_team_id = ? or away_team_id = ?', team.id, team.id) }, class_name: 'Game'

它肯定不会起作用,因为 Rails 仍然会作为JOIN games ON games.team_id = teams.id 仅在查询中添加WHERE子句并不能解决这个问题。 由于 ActiveRecord 实际上创建了各种不同的查询,因此无法简单地提供不同的连接。

使这项工作成为可能的是添加一个实例方法:

class Game < ApplicationRecord
  def users
    User.joins(:teams)
        .where(teams: { id: home_team.id })
        .or(Team.where(id: away_team.id))
  end
end

由于它不是实际关联,因此您无法通过它加入或使用一种急切加载来避免 n+1 查询。

如果您确实想创建一个可以通过加入的关联,则需要在游戏和团队之间添加一个连接表。

class Team < ApplicationRecord
  # ...
  has_many :game_teams
  has_many :games, through: :game_teams
end

# rails g model game_team team:belongs_to game:belongs_to score:integer 
class GameTeam < ApplicationRecord
  belongs_to :team
  belongs_to :game
end

class Game < ApplicationRecord
  has_many :game_teams
  has_many :teams, through: :game_teams
  has_many :users, through: :teams
end

这是一个更好的主意,因为它为您提供了一个合乎逻辑的位置来记录每个团队的得分。

顺便说一句,如果球队的组成可以改变并且准确的记录保持很重要,您实际上可能需要额外的连接表,因为比赛进行时的阵容可能实际上与当前阵容不匹配。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM