Многоуровневые ассоциации в рельсах - PullRequest
1 голос
/ 01 сентября 2009

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

Ответы [ 2 ]

7 голосов
/ 01 сентября 2009

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

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

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

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, которая может произойти дальше (я имею в виду на самом деле? он знает, как объединить больше условий? Иногда он делает подзапрос, подзапрос? Это просто не нужно здесь?).

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

0 голосов
/ 01 сентября 2009

Скажем, что у вас есть модель 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.

...