2012-03-22 12 views
5

cercando di refactoring del codice per fornire all'associazione pulitaRails 3.2.2 - has_many attraverso

Un gioco ha un HOME_TEAM e un AWAY_TEAM

una squadra ha molti giochi come HOME_TEAM o un AWAY_TEAM

Association tra GAME e TEAM è un HABTM diretto MA DEVO denotare quale dei due TEAM associati a GAME è HOME_TEAM e che è AWAY_TEAM. L'ho fatto aggiungendo campi e associazioni supplementari, ma questo è ovvio molto bagnato piuttosto che asciutto. So che la risposta è arrivata, ma sembra che abbia avuto una crisi cerebrale e non riesco a capirlo.

Fondamentalmente voglio essere in grado di fare Game.teams (restituisce collezione di entrambe le squadre) e Game.home_team (ottenere e impostare una squadra per HOME_TEAM) e Game.away_team (ottenere e impostare una squadra per AWAY_TEAM)

dispiace di porre una query suono semplice ma è appena ricevuto da me

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 

Tutto l'aiuto molto apprezzato

Peter

+2

Vuoi veramente che HomeTeam e AwayTeam siano classi separate? E, al momento, tabelle DB separate? – Chowlett

+0

No - è solo un bodge. Probabilmente voglio una tabella games_teams con un boolean home_team che penso ... – pshear0

risposta

7

Per fare ciò che vuoi fare, devi usare uno has_many :through invece di hatbm. Vedi here per maggiori informazioni. In breve, la cosa buona è che puoi aggiungere altre variabili alla tabella dei join. Nel tuo caso, un booleano chiamato home_team.

Quindi ecco cosa farei. In primo luogo, creare una tabella di associazione (dal momento che non ho molta fantasia, lo chiamerò partecipazione):

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

Come si può vedere, a differenza vostra tavola gamesteams, questo ha un id. E puoi aggiungere attributi ad esso. Poi, vorrei utilizzare questi modelli:

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 

in modo da ottenere le squadre di un gioco, si fa @game.teams.

Ora, per ottenere HOME_TEAM e AWAY_TEAM, aggiungere questi metodi per il vostro modello di gioco:

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 

E poi sarete in grado di fare @game.home_team e @game.away_team.

modifica di Pietro: Ok, quindi per MySQL dovrete utilizzare diversi dove dichiarazioni:

self.teams.joins (partecipanti): .dove ("? Participants.home_team =" true primo. self.teams.joins (: partecipanti) .where ("participants.home_team IS NULL"). first

Posso usare "=?", vero e "! =?", vero - O - NON È NULL e IS NULL

Penso che per falso dovresti provare a usare where("participants.home_team = ?", false)

Ok, quindi ci sono almeno 2 modi per configurare i tuoi team.

  1. Si lascia all'utente di scegliere quale squadra sta giocando casa
  2. utente si assume la prima squadra è la squadra di casa

Se si va per il numero 1, è necessario utilizzare un pulsante di opzione per lasciare che il l'utente decide. Qualcosa di simile a questo:

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

Quindi, se params[:home_team] == 1, la prima squadra è la squadra di casa, se params[:home_team] == 2, la seconda squadra è la squadra di casa.

Se si va per il numero 2, poi, si dovrebbe avere qualcosa di simile nella vostra forma non aggiungere le squadre al vostro gioco:

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

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

Allora nel vostro controller si può fare qualcosa di simile

@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 - questo suona molto promettente. Sto costruendo nel mio letto di prova mentre parliamo. Vi dirò se questo funziona e accetta. Grazie per la tua risposta – pshear0

+0

Ho modificato la mia domanda e l'ho testata davvero questa volta. Funziona correttamente, provalo e dimmi come è andata! – Ashitaka

+0

Ciao Ashitaka, ancora lavorando su questo problema. Usando la tua soluzione mi sono imbattuto in problemi con MySql e ho dovuto apportare un paio di modifiche alle clausole where – pshear0

Problemi correlati