Rails ActiveRecord два поля, каждое из которых ссылается на одну и ту же таблицу - PullRequest
0 голосов
/ 31 января 2020

У меня есть класс Player, который я хочу иметь свойства high_school_team и club_team. Итак, я думаю, что Player будет иметь свойства high_school_team_id и club_team_id, которые указывают на соответствующую команду. Я пытаюсь сделать это в следующей миграции, но она не работает.

class CreatePlayers < ActiveRecord::Migration[6.0]
  def change
    create_table :players do |t|
      t.string :first_name
      t.string :middle_name
      t.string :last_name
      t.decimal :height
      t.decimal :weight
      t.date :birthday
      t.references :team, :high_school_team, foreign_key: true
      t.references :team, :club_team, foreign_key: true
      t.decimal :gpa
      t.string :class_year
      t.string :intended_major
      t.string :email
      t.string :phone_number
      t.text :notes

      t.timestamps
    end
  end
end

Выдает следующую ошибку:

code/scout-db [master●] » rails db:migrate
== 20191218003854 CreatePlayers: migrating ====================================
-- create_table(:players)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

you can't define an already defined column 'team_id'.
/Library/Ruby/Gems/2.6.0/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract/schema_definitions.rb:372:in `column'
...

HighSchoolTeam и ClubTeam - модели которые делают наследование одной таблицы с Team.

Я не понимаю, почему я получаю ошибку. документы , кажется, говорят, что первый аргумент для t.referenes это table_name, а второй ref_name. :team - это имя таблицы, и я хочу, чтобы ссылки были high_school_team_id и club_team_id.

Когда я переключаю порядок аргументов на t.references, он все равно не работает. Почему-то выдает такую ​​же ошибку: you can't define an already defined column 'team_id'..

Ответы [ 2 ]

1 голос
/ 31 января 2020

Похоже, вы путаете SchemaStatement#add_reference и TableDefinition#references, которые имеют совершенно разные подписи.

Если вы хотите настроить столбец внешнего ключа, где таблица не может быть получена из имени столбца (первый аргумент), который вы просто передаете foreign_key: { to_table: :teams}.

class CreatePlayers < ActiveRecord::Migration[6.0]
  def change
    create_table :players do |t|
      t.references :high_school_team, foreign_key: { to_table: :teams}
      t.references :club_team, foreign_key: { to_table: :teams}
    end
  end
end

t.references :high_school_team, index: true, как рекомендовано другими ответами, НЕ эквивалентно. Это просто добавляет индекс к столбцу, но без ограничения внешнего ключа.

Затем вы можете настроить ассоциации в Player следующим образом:

class Player < ApplicationRecord
  belongs_to :high_school_team, class_name: 'Team'
  belongs_to :club_team, class_name: 'Team'
end

Вы не можете использовать одну ассоциацию has_many :players на другом конце, хотя в качестве столбца внешнего ключа можно указать либо players.high_school_team_id, либо players.club_team_id.

class Team
  has_many :high_school_team_players, 
     foreign_key: :high_school_team_id,
     class_name: 'Player'
  has_many :club_team_players, 
     foreign_key: :club_team_id,
     class_name: 'Player'
end

Но на самом деле лучшей альтернативой, во-первых, была бы установка таблицы соединения:

class Player
  has_many :placements
  has_one :high_school_team, 
    through: :placements,
    source: :team
    class_name: 'Team'
  has_one :club_team, 
    through: :placements,
    source: :team
    class_name: 'Team'
end

class Placement
  belongs_to :player
  belongs_to :team
end

class Team
  has_many :placements
  has_many :players, through: :placements  
end
0 голосов
/ 31 января 2020

Упомянутый вами do c говорит о случае, когда вам нужно добавить ссылку на существующую таблицу.

Для добавления ссылки на новую таблицу:

t .references: team,: high_school_team, foreign_key: true

Этот фрагмент кода неправильный. Вместо этого необходимо добавить

t.references :high_school_team, foreign_key: {to_table: :teams}

to_table, чтобы добавить ссылочную целостность базы данных

Таким образом, ваша миграция будет выглядеть следующим образом:

class CreatePlayers < ActiveRecord::Migration[6.0]
  def change
    create_table :players do |t|
      ....
      t.references :high_school_team, foreign_key: {to_table: :teams}
      t.references :club_team, foreign_key: {to_table: :teams}
      ....
    end
  end
end
...