2012-03-22 13 views
5

tratando de refactorizar código para proporcionar asociación limpiaRails 3.2.2 - has_many través

un juego tiene un HOME_TEAM y un AWAY_TEAM

un equipo tiene muchos juegos como HOME_TEAM o un AWAY_TEAM

Asociación entre GAME y TEAM es una HABTM directa, PERO necesito denotar cuál de los dos EQUIPOS asociados con un JUEGO es el HOME_TEAM y cuál es el AWAY_TEAM. Lo hice agregando campos y asociaciones adicionales, pero esto es obvio, muy húmedo en lugar de seco. Sé que la respuesta está completa, pero parece que tuve un colapso cerebral y no puedo entender esto.

Básicamente quiero ser capaz de hacer Game.teams (devuelve colección de ambos equipos) y Game.home_team (obtener y configurar un equipo para HOME_TEAM) y Game.away_team (obtener y configurar un equipo para AWAY_TEAM)

lo sentimos plantear una consulta que suena tan directa, pero sólo tiene lejos de mí

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 

Toda ayuda muy apreciada

Peter

+2

¿Realmente desea que HomeTeam y AwayTeam sean clases separadas? Y, en la actualidad, ¿tablas de DB separadas? – Chowlett

+0

No, es solo una burla. Probablemente quiero una tabla games_teams con un booleano home_team, creo ... – pshear0

Respuesta

7

Para hacer lo que quiere hacer, debe usar un has_many :through en lugar de hatbm. Ver here para más información. En resumen, lo bueno es que puede agregar otras variables a la tabla de combinaciones. En tu caso, un booleano llamado home_team.

Así que esto es lo que haría. En primer lugar, crear una tabla de asociación (ya que no tengo mucha imaginación, voy a llamarlo participación):

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

Como se puede ver, a diferencia de su mesa gamesteams, éste tiene un ID. Y puedes agregarle atributos. Entonces, me gustaría utilizar estos modelos:

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 

Así que para los equipos de un juego, lo hace @game.teams.

Ahora, para obtener HOME_TEAM y AWAY_TEAM, añadir estos métodos para su modelo de juego:

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 

Y entonces usted será capaz de hacer @game.home_team y @game.away_team.

edición de Pedro: Ok, así que para MySQL tendrá que utilizar diferentes donde declaraciones:

self.teams.joins (participantes): .donde ("? Participants.home_team =", verdadera) .primero self.teams.joins (: participantes) .where ("participantes.home_team IS NULL"). Primero

Puedo usar "=?", verdadero y "! =?", verdadero - OR-- NO ES NULO y ES NULO

Creo que es falso, debe intentar usar where("participants.home_team = ?", false)

Ok, entonces hay al menos 2 formas de configurar sus equipos.

  1. deja que el usuario elegir qué equipo está jugando en casa
  2. usted asume el primer equipo es el equipo local

Si vas para el número 1, se debe utilizar un botón de opción para permitir la el usuario decide Algo como esto:

<%= 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 %> 

Así que si params[:home_team] == 1, el primer equipo es el equipo local, si params[:home_team] == 2, el segundo equipo es el equipo local.

Si vas para el número 2, a continuación, usted debe tener algo como esto en su forma no agregar los equipos a su juego:

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

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

Así que en su controlador puede hacer algo como

@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) 
+0

Ashitaka - esto suena muy prometedor. Estoy construyendo en mi banco de pruebas mientras hablamos. Te dejaré saber si esto funciona y lo acepto. Gracias por su respuesta – pshear0

+0

Edité mi pregunta y realmente la probé esta vez. Está funcionando correctamente, pruébalo y cuéntame cómo fue. – Ashitaka

+0

Hola Ashitaka, todavía estoy trabajando en este problema. Utilizando su solución me encontré con problemas con MySql y tuve que hacer un par de cambios a las cláusulas where – pshear0

Cuestiones relacionadas