Rails - добавление двунаправленных отношений - PullRequest
3 голосов
/ 16 октября 2019

Я пытаюсь настроить пример приложения, которое отслеживает футбольные матчи. Там в настоящее время 3x столов:

  • Земля - ​​Родина конкретной команды
  • Команда - Сама фактическая команда
  • Игра - Игра, в которой будут двакоманды

Я могу успешно запросить «Какие две команды играют в этой игре?», но я изо всех сил пытаюсь повернуть вспять и спросить «В каких играх играла эта команда?»

Я настроил новый проект rails с Rails 5.1.7 и использовал консоль Rails для запроса данных.

Миграции

Земля

  def change
    create_table :grounds do |t|
      t.string :ground_name
      t.string :ground_location
      t.belongs_to :team
      t.timestamps
    end
  end
end

Игра

  def change
    create_table :games do |t|
      t.timestamps
      t.datetime :game_time
      t.belongs_to :team_one
      t.belongs_to :team_two
    end
  end
end

Команда

  def change
    create_table :teams do |t|
      t.string :team_name
      t.timestamps
    end
  end
end

Модели

Земля

class Ground < ApplicationRecord
  belongs_to :team
end

Игра

class Game < ApplicationRecord
  belongs_to :team_one, :class_name => "Team"
  belongs_to :team_two, :class_name => "Team"
  has_many :teams
end

Команда

class Team < ApplicationRecord
  has_one :ground
end

Я могу успешно запросить:

g1 = Game.new
g1.team_one = Team.first
g1.team_two = Team.second
g1.save

Game.first.team_one -> Correctly spits out team
Game.first.team_two -> Correctly spits out team

Я хотел бы получить списокигр для команды:

Team.first.games
  Team Load (0.0ms)  SELECT  "teams".* FROM "teams" ORDER BY "teams"."id" ASC LIMIT ?  [["LIMIT", 1]]
NoMethodError: undefined method `games' for #<Team:0x5a53fa0>
        from (irb):1


Я определенно что-то упускаю, но надеюсь, что это возможно. Если бы кто-нибудь мог пролить свет на это, я был бы очень благодарен! Заранее спасибо.

Ответы [ 4 ]

1 голос
/ 16 октября 2019

Вы можете получить игры, как показано ниже. unscope важно. Запрос не будет работать правильно без unscope.

class Team < ApplicationRecord
  has_one :ground
  has_many :games, lambda { |team|
    unscope(:where)
      .where('team_one_id = ? OR team_two_id = ?', team.id, team.id)
  }
end

t1 = Team.first
t1.games
#=> [Game id: 1, team_one_id: 1, team_two_id: 2, ..]
t2 = Team.second
t2.games
#=> [Game id: 1, team_one_id: 1, team_two_id: 2, ..]
0 голосов
/ 16 октября 2019

Прежде всего, ответьте на простой случай: используя вашу модель Game, мы можем легко перечислить игры, в которые команда играет дома, и выездные игры (надеюсь, это правильный термин). Я полагаю, из вашей структуры данных, что команда 1 ведет игру. Таким образом, мы получаем что-то вроде:

class Team 
  has_many :home_games, class_name: 'Game', foreign_key: :team_one 
  has_many :away_games,  class_name: 'Game', foreign_key: :team_two 
end 

Но для перечисления всех игр команды мы можем сделать несколько вещей:

Наименее эффективный, но очень простой /Наивная реализация:

 def games 
   home_games + away_games 
 end 

, которая будет извлекать все домашние и выездные игры, конвертировать в массивы и добавлять / объединять массивы, НО впоследствии невозможно добавить where, сортировку и т.д. ...

Лучше использовать базу данных

def games 
  Game.where("team_one_id = ? or team_two_id = ?", self.id, self.id) 
end 

(в rails 5 вы также можете записать это как Game.where(team_one_id: self.id).or(Game.where(team_two_id: self.id)), но я все же предпочитаю старый способ как более читаемый и менее набираемый)

Тогда вы сможете написать что-то вроде

@team = Team.find(params[:id])
@games = @team.games.order(:game_time)
0 голосов
/ 16 октября 2019
class Game < ApplicationRecord
  belongs_to :team_one, :class_name => "Team"
  belongs_to :team_two, :class_name => "Team"

  scope :by_team, -> (team) { 
    where(team_one_id: team.id).or(where(team_two_id: team.id)) 
  }
end

Game.by_team(Team.first)
0 голосов
/ 16 октября 2019

Но я изо всех сил пытаюсь повернуть вспять и спросить «В какие игры играла эта команда?»

Если вы хотите найти все игры, в которых играла команда, вы можетеиспользуйте метод #or следующим образом:

team = Team.find(1) # or any other criteria to find the team you want to get the games for

Game.where(team_one: team).or(Game.where(team_two: team))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...