Rails 3.2.2 - has_many через - PullRequest
       1

Rails 3.2.2 - has_many через

5 голосов
/ 22 марта 2012

пытается изменить код для обеспечения чистой ассоциации

У ИГРЫ есть HOME_TEAM и AWAY_TEAM

У КОМАНДЫ есть много ИГР как HOME_TEAM или AWAY_TEAM

Ассоциация междуИГРА и КОМАНДА - это простой HABTM, НО мне нужно указать, какая из двух КОМАНД, связанных с ИГРОЙ, является HOME_TEAM, а какая - AWAY_TEAM.Я сделал это, добавив дополнительные поля и ассоциации, но это очевидно очень влажный, а не сухой.Я знаю, что ответ на этот вопрос исчерпан, но, похоже, у меня произошел обвал мозга, и я не могу полностью разобраться в этом.

В основном я хочу иметь возможность делать Game.teams (возвращает сборник обеих команд) и Game.home_team (получить и установить КОМАНДУ в home_team) и Game.away_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 Ответ

7 голосов
/ 22 марта 2012

Чтобы сделать то, что вы хотите, вы должны использовать has_many :through вместо hatbm. См. здесь для получения дополнительной информации. Короче говоря, хорошо, что вы можете добавить другие переменные в таблицу соединений. В вашем случае логическое значение home_team.

Так вот, что бы я сделал. Во-первых, создайте таблицу ассоциаций (так как у меня не так много воображения, я назову это участием):

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

Как видите, в отличие от вашей таблицы игровых команд, у этого есть идентификатор. И вы можете добавить атрибуты к нему. Тогда я бы использовал эти модели:

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.

Правка Питера: Хорошо, так что для mysql вам придется использовать разные где заявления:

self.teams.joins (: members) .where ("members.home_team =?", True) .first self.teams.joins (: members) .where ("members.home_team IS NULL"). first

Я могу использовать "=?", True и "! =?", True --OR-- NOT NULL и ЕСТЬ НУЛЬ

Я думаю, что для false вы должны попробовать использовать where("participants.home_team = ?", false)

Хорошо, так что есть как минимум 2 способа настроить ваши команды.

  1. Вы позволяете пользователю выбирать, какая команда играет дома
  2. Вы предполагаете, что первая команда - хозяева

Если вы выберете номер 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...