2012-03-22 11 views
5

próbuje byłaby kod, aby zapewnić czysty asocjacjiRails 3.2.2 - has_many poprzez

GRA ma HOME_TEAM oraz AWAY_TEAM

ZESPÓŁ ma wiele gier jak HOME_TEAM lub AWAY_TEAM

Stowarzyszenia pomiędzy GAME a TEAM jest prostym HABTM, ALE muszę określić, który z dwóch ZESPOków powiązanych z GRAMI jest HOME_TEAM, a który jest AWAY_TEAM. Zrobiłem to, dodając dodatkowe pola i skojarzenia, ale jest to oczywiste, że jest bardzo mokry, a nie suchy. Wiem, że odpowiedź jest w toku, ale wydaje mi się, że miałem już problem z mózgiem i nie mogę sobie z tym poradzić.

Zasadniczo chcę być w stanie zrobić Game.teams (zwraca kolekcję obu zespołów) i Game.home_team (GET i ustawić zespół do HOME_TEAM) i Game.away_team (get i ustawić zespół do away_team)

Niestety stwarzać takie proste zapytanie brzmiące, ale to jest po prostu dostał ode mnie

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 

Wszystko pomoc mile widziana

Peter

+2

Czy naprawdę chcesz, aby HomeTeam i AwayTeam były oddzielnymi klasami? A teraz oddzielne tabele DB? – Chowlett

+0

Nie - to tylko bodge. Prawdopodobnie chcę tabeli games_teams z boolean home_team myślę, że ... – pshear0

Odpowiedz

7

Aby zrobić to, co chcesz, powinieneś użyć has_many :through zamiast hatbm. Aby uzyskać więcej informacji, patrz here. W skrócie, dobrą rzeczą jest to, że możesz dodać inne zmienne do tabeli złączeń. W twoim przypadku boolean nazywa się home_team.

Oto, co zrobię. Najpierw należy utworzyć tabelę asocjacji (ponieważ nie mam dużo wyobraźni, zadzwonię to uczestnictwo):

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

Jak widać, w przeciwieństwie do stolika gamesteams, ten ma id. Możesz dodać do niego atrybuty. Następnie chciałbym używać tych modeli:

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 

Więc aby uzyskać zespoły gry, robisz @game.teams.

Teraz, aby dostać HOME_TEAM i away_team, dodać te metody do modelu gry:

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 

I wtedy będziesz w stanie zrobić @game.home_team i @game.away_team.

edit Piotra: Ok, więc dla mysql musisz użyć inny gdzie oświadczenia:

self.teams.joins (: Uczestnicy) .gdzie ("? Participants.home_team =" prawdziwa) .pierwszy self.teams.joins (: uczestników) .where ("participants.home_team IS NULL"). najpierw

Mogę użyć "=?", true i "! =?", true - LUB - NIE JEST NULL i IS NULL

Uważam, że pod względem fałszywości powinieneś spróbować użyć where("participants.home_team = ?", false)

OK, więc istnieją co najmniej 2 sposoby na skonfigurowanie zespołów.

  1. można pozwolić użytkownikowi wybrać, która drużyna gra w domu
  2. założyć pierwszy zespół to zespół gospodarzy

Jeśli pójdziesz za numer 1, należy użyć przycisku radiowego pozwolić użytkownik decyduje. Coś takiego:

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

Więc jeśli params[:home_team] == 1, pierwszy zespół jest drużyna gospodarzy, jeśli params[:home_team] == 2, drugi zespół jest drużyna gospodarzy.

Jeśli pójdziesz na numer 2, a następnie, trzeba mieć coś takiego w swojej formie nie dodać drużyn do gry:

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

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

Więc w kontrolerze można zrobić coś podobnego

@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 - brzmi to bardzo obiecująco. Kiedy mówimy, buduję na moim testowym łóżku. Dowiesz Ci, czy to działa i akceptuj. Dzięki za odpowiedź – pshear0

+0

Edytowałem moje pytanie i naprawdę przetestowałem to tym razem. Działa poprawnie, spróbuj i powiedz mi, jak poszło! – Ashitaka

+0

Cześć Ashitaka, wciąż pracuję nad tym problemem. Korzystając z tego rozwiązania, natknąłem się na problemy z MySql i musiałem wprowadzić kilka zmian w klauzulach dotyczących miejsc, gdzie – pshear0

Powiązane problemy