Многоуровневые ассоциации в рельсах

Я создаю приложение для отслеживания футбольных команд в течение всего сезона. но я застрял на дизайне базы данных. В одном матче есть команда хозяев и команда гостей. Я создал модель прибора, у которой есть два внешних ключа - home_team и away_team, но я не могу заставить ассоциацию работать правильно. есть идеи? Каждый матч принадлежит лиге.

2 ответа

Решение

Простой ответ:

class Fixture < ActiveRecord::Base
  belongs_to :home_team, :class_name => "Team", :foreign_key => :home_team
  belongs_to :away_team, :class_name => "Team", :foreign_key => :away_team
end

class Team < ActiveRecord::Base
  has_many :fixtures
end

Но это не хорошо, если вы, потому что Team.fixtures не будет работать.

class Team < ActiveRecord::Base
  has_many :home_fixtures, :class_name => "Fixtures", :foreign_key => :home_team
  has_many :away_fixtures, :class_name => "Fixtures", :foreign_key => :away_team
end

даст вам две коллекции... но их объединение должно произойти в рубине, что будет неприлично.

class Team < ActiveRecord::Base
  def fixtures(*args)
    home_fixtures.all(*args) + away_fixtures.all(*args)
  end
end

С этим тоже есть свои проблемы, сортировка и лимит будут забиты (хех, каламбур, кто знал?).

class Team < ActiveRecord::Base
  has_many :fixtures, :finder_sql => 'SELECT * FROM fixtures where (home_team = #{id} or away_team = #{id})'
  has_many :home_fixtures, :class_name => "Fixtures", :foreign_key => :home_team
  has_many :away_fixtures, :class_name => "Fixtures", :foreign_key => :away_team
end

Это некрасиво, но может просто сработать. Похоже, что finder_sql делает то, что нужно.

Другой вариант - использовать named_scope:

class Fixture < ActiveRecord::Base
  named_scope :for_team_id, lambda{|team_id| {:conditions => ['(home_team = ? or away_team = ?)', team_id, team_id]} }
  belongs_to :home_team, :class_name => "Team", :foreign_key => :home_team
  belongs_to :away_team, :class_name => "Team", :foreign_key => :away_team
end

class Team < ActiveRecord::Base
  def fixtures
    Fixtures.for_team_id(id)
  end
end

Это последнее решение, которое я придерживаюсь, потому что это область действия, которая будет вести себя как ассоциация только для чтения, и предотвращает :finder_sql причудливость, которая может произойти в дальнейшем (я имею в виду на самом деле? Как он знает, как объединить больше условий? Иногда он делает подзапрос, подзапрос? Это просто не нужно здесь?).

Надеюсь это поможет.

Скажи, что у тебя есть Team модель и Something Модель, последняя будет иметь home_team_id а также away_team_id,

class Something < ActiveRecord::Base
  belongs_to :home_team, :class_name => 'Team'
  belongs_to :away_team, :class_name => 'Team'

Вы будете ссылаться на них как something.away_team а также something.home_team,

Другие вопросы по тегам