Rails-添加双向关系

时间:2019-10-16 11:22:28

标签: ruby-on-rails activerecord migration

我正在尝试建立一个跟踪足球比赛的示例应用程序。当前有3张桌子:

  • 地面-特定团队的主场
  • 团队-实际的团队本身
  • 游戏-一场比赛,将容纳两支球队

我可以成功查询“哪个球队参加了这场比赛?”,但我正在努力扭转这种状况,并问“这个球队参加了哪些比赛?”

我已经用Rails 5.1.7设置了一个新的Rails项目,并一直在使用Rails控制台查询数据。

迁移

地面

  def change
    create_table :grounds do |t|
      t.string :ground_name
      t.string :ground_location
      t.belongs_to :team
      t.timestamps
    end
  end
end

游戏

  def change
    create_table :games do |t|
      t.timestamps
      t.datetime :game_time
      t.belongs_to :team_one
      t.belongs_to :team_two
    end
  end
end

团队

  def change
    create_table :teams do |t|
      t.string :team_name
      t.timestamps
    end
  end
end

模型

地面

class Ground < ApplicationRecord
  belongs_to :team
end

游戏

class Game < ApplicationRecord
  belongs_to :team_one, :class_name => "Team"
  belongs_to :team_two, :class_name => "Team"
  has_many :teams
end

团队

class Team < ApplicationRecord
  has_one :ground
end

我可以成功查询:

g1 = Game.new
g1.team_one = Team.first
g1.team_two = Team.second
g1.save

Game.first.team_one -> Correctly spits out team
Game.first.team_two -> Correctly spits out team

我希望能够获得一支球队的比赛清单:

Team.first.games
  Team Load (0.0ms)  SELECT  "teams".* FROM "teams" ORDER BY "teams"."id" ASC LIMIT ?  [["LIMIT", 1]]
NoMethodError: undefined method `games' for #<Team:0x5a53fa0>
        from (irb):1


我肯定会缺少一些东西,但希望这是可能的。如果有人能对此有所启示,我将非常感谢!预先感谢。

4 个答案:

答案 0 :(得分:1)

您可以获取以下游戏。 unscope很重要。如果没有取消范围,查询将无法正确运行。

class Team < ApplicationRecord
  has_one :ground
  has_many :games, lambda { |team|
    unscope(:where)
      .where('team_one_id = ? OR team_two_id = ?', team.id, team.id)
  }
end

t1 = Team.first
t1.games
#=> [Game id: 1, team_one_id: 1, team_two_id: 2, ..]
t2 = Team.second
t2.games
#=> [Game id: 1, team_one_id: 1, team_two_id: 2, ..]

答案 1 :(得分:0)

  

但是我正在努力扭转这种局面,并问“哪个比赛有这支球队   玩过吗?”

如果您想查找一个团队参加过的所有比赛,可以使用#or方法,如下所示:

team = Team.find(1) # or any other criteria to find the team you want to get the games for

Game.where(team_one: team).or(Game.where(team_two: team))

答案 2 :(得分:0)

class Game < ApplicationRecord
  belongs_to :team_one, :class_name => "Team"
  belongs_to :team_two, :class_name => "Team"

  scope :by_team, -> (team) { 
    where(team_one_id: team.id).or(where(team_two_id: team.id)) 
  }
end

Game.by_team(Team.first)

答案 3 :(得分:0)

首先,回答一个简单的案例:使用您的Game模型,我们可以轻松列出球队在主场比赛和客场比赛中的比赛(我希望这是正确的术语)。我认为,根据您的数据结构,第1队将主持比赛。这样我们就得到了:

class Team 
  has_many :home_games, class_name: 'Game', foreign_key: :team_one 
  has_many :away_games,  class_name: 'Game', foreign_key: :team_two 
end 

但是要列出团队的所有游戏,我们可以做一些事情:

效率最低但非常简单/天真的实现:

 def games 
   home_games + away_games 
 end 

这将获取所有本垒打游戏,转换为数组并添加/连接数组,但是以后无法添加where,排序等等...

更好的方法是使用数据库

def games 
  Game.where("team_one_id = ? or team_two_id = ?", self.id, self.id) 
end 

(在rails 5中,您也可以将其写为Game.where(team_one_id: self.id).or(Game.where(team_two_id: self.id)),但我仍然更喜欢旧方法,因为它更具可读性和更少的键入性)

然后,您将可以编写类似

的内容
@team = Team.find(params[:id])
@games = @team.games.order(:game_time)