Rails 3.2.2 - has_many通过

时间:2012-03-22 11:56:00

标签: ruby-on-rails

尝试重构代码以提供干净的关联

GAME有一个HOME_TEAM和一个AWAY_TEAM

TEAM有许多游戏作为HOME_TEAM或AWAY_TEAM

GAME和TEAM之间的关联是直接的HABTM但是我需要表示与GAME相关联的两个TEAM中的哪一个是HOME_TEAM,哪个是AWAY_TEAM。我通过添加额外的字段和关联来做到这一点,但这显然非常潮湿而不是干燥。我知道答案已经过去,但我似乎已经脑子崩溃了,并且无法完全理解这一点。

基本上我希望能够做Game.teams(返回两个团队的集合)和Game.home_team(获取并设置TEAM到home_team)和Game.away_team(获取并设置TEAM到away_team)

很抱歉提出这样一个直截了当的声音查询,但它离我而去

class Game < ActiveRecord::Base
  belongs_to :home_team
  belongs_to :away_team
  has_and_belongs_to_many :teams
end

class HomeTeam < ActiveRecord::Base
  belongs_to :team
  has_one :games
end

class AwayTeam < ActiveRecord::Base
  belongs_to :team
  has_one :games
end

class Team < ActiveRecord::Base
  has_and_belongs_to_many :games
  has_many :away_teams
  has_many :home_teams
end 

所有帮助非常感谢

彼得

1 个答案:

答案 0 :(得分:7)

要执行您要执行的操作,您应使用has_many :through代替hatbm。有关详细信息,请参阅here。简而言之,好处是您可以将其他变量添加到连接表中。在您的情况下,一个名为home_team的布尔值。

所以这就是我要做的。首先,创建一个关联表(因为我没有太多的想象力,我称之为参与):

create_table :participations, do |t|
  t.integer :game_id, :null => false
  t.integer :team_id, :null => false
  t.boolean :home_team
end

正如您所看到的,与您的游戏团队表不同,此表具有ID。您可以为其添加属性。 然后,我会使用这些模型:

class Participation < ActiveRecord::Base
  belongs_to :game
  belongs_to :team
end

class Game < ActiveRecord::Base
  has_many :participations, :dependent => :destroy
  has_many :teams, :through => :participations
end

class Team < ActiveRecord::Base
  has_many :participations, :dependent => :destroy
  has_many :games, :through => :participations
end

为了获得游戏团队,你可以@game.teams

现在,要获得home_team和away_team,请将这些方法添加到您的游戏模型中:

def home_team
  self.teams.joins(:participations).where("participations.home_team IS ?", true).first
end

def away_team
  self.teams.joins(:participations).where("participations.home_team IS ?", false).first
end

然后您就可以@game.home_team@game.away_team

  

Peter的编辑:好的,所以对于mysql,你将不得不使用不同的地方   语句:

     

self.teams.joins(:participant).where(“participant.home_team =?”,true).first   self.teams.joins(:participant).where(“participant.home_team IS NULL”)。first

     

我可以使用“=?”,true和“!=?”,true - 或 - IS NOT NULL和   IS NULL

我认为你应该尝试使用where("participants.home_team = ?", false)

好的,所以至少有两种方法可以设置你的团队。

  1. 您让用户选择正在回家的队伍
  2. 您认为第一支球队是主队
  3. 如果你选择1号,你应该使用一个单选按钮让用户决定。像这样:

    <%= label_tag :home, 'Home Team' %><br />
    <%= label_tag :home_team_1, 'Team 1' %><%= radio_button_tag :home_team, 1 %>
    <%= label_tag :home_team_2, 'Team 2' %><%= radio_button_tag :home_team, 2 %>
    

    因此,如果params[:home_team] == 1,第一个团队是主队,如果params[:home_team] == 2,则第二个团队是主队。

    如果你选择2号,那么,你应该在你的表格中有类似的东西,将你的球队添加到你的游戏中:

      <%= label_tag :name, 'Home Team' %>
      <%= text_field_tag :name, nil, :name => "home[]" %>
    
      <%= label_tag :name, 'Away Team' %>
      <%= text_field_tag :name, nil, :name => "away[]" %>
    

    然后在您的控制器中,您可以执行类似

    的操作
    @game = Game.new(params[:game])
    
    home = Team.create(params[:home])
    # or
    home = Team.find_or_create_by_name(params[:home][:name])
    @game.participations.create(:team_id => home.id, :home_team => true or 1)
    
    away = Team.find_or_create_by_name(params[:away][:name])
    @game.participations.create(:team_id => away.id, :home_team => false or 0)