Миграция Rails: ссылки с альтернативным именем?

121

Итак, у меня есть такая create_table для курсов в школе:

create_table :courses do |t|
  t.string :name
  t.references :course
  t.timestamps
end

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

has_many :transferrable_as # A Course
has_many :same_as          # Another Course

Могу я сказать следующее?

t.references :transferrable_as, :as=> :course
зеркало
источник

Ответы:

161

Вы можете сделать все это в начальном определении миграции / столбца (по крайней мере, в настоящее время в Rails 5):

t.references :transferable_as, index: true, foreign_key: {to_table: :courses}
t.references :same_as, index: true, foreign_key: {to_table: :courses}
Райан
источник
10
Это работает в Rails 5.1, и ни одно из других предложений не работает. Он намного чище и кажется правильным.
Стивенмердок
2
Я использую Rails 5.1.4, но это не работает. Когда я указываю foreign_keyопцию при создании таблицы таким образом, возникает ошибка, говорящая, что та самая таблица, которую я создаю, не существует ... Так что я подозреваю, что на самом деле она не поддерживается официальным API.
Quv
3
Я также читал, что indexэто уже добавлено во внешние ключи в Rails stackoverflow.com/questions/39769981/…
Джонатан Рейес
99

Сделать это можно так:

create_table :courses do |t|
  t.string :name
  t.references :transferrable_as
  t.references :same_as
  t.timestamps
end

или используя t.belongs_toкак псевдоним дляt.references

Вы не можете добавить foreign_key: trueк этим двум ссылкам строки. Если вы хотите пометить их как внешние ключи на уровне базы данных, вам необходимо выполнить миграцию следующим образом:

add_foreign_key :courses, :courses, column: :transferrable_as_id
add_foreign_key :courses, :courses, column: :same_as_id

Обновить

В Rails 5.1 и выше вы можете добавить внешний ключ в миграцию в create_tableблоке следующим образом:

create_table :courses do |t|
  t.string :name
  t.references :transferrable_as, foreign_key: { to_table: 'courses' }
  t.references :same_as, foreign_key: { to_table: 'courses' }
  t.timestamps
end
Тоби 1 Кеноби
источник
5
То, что я не могла добавить foreign_key: trueк ссылкам, сбивало меня с толку. Добавление add_foreign_keyи указание имени столбца для них помогло.
Мэтью Кларк,
Это работает в Rails "из коробки"? Согласно stackoverflow.com/a/22384289/239657 , для этого требуется schema_plusдрагоценный камень. В документации add_reference Rails не упоминаются параметры a: links .
Бени Чернявский-Паскин
1
Я не слежу за тем, для чего предназначена эта references:опция (в отличие от того, t.referencesразве это не будет актуально только на уровне модели, с учетом соображений foreign_key add_foreign_key?
MCB
1
@MCB t.referencesговорит: «Добавьте в эту таблицу поле, которое является первичным ключом другой таблицы». references:Опция указывает , что какая таблица это первичный ключ (требуется , если не ясно , по имени поля). Здесь add_foreign_keyфункция сообщает базе данных о принудительной ссылочной целостности.
Toby 1 Kenobi
2
@MCB, спустя столько времени, я понимаю, что ты все время был прав. Ваш первый комментарий выше совершенно правильный - add_foreign_keyстроки заботятся о том, чтобы сообщить базе данных, что является внешним ключом и чем. references:Параметр не делает ничего.
Тоби 1 Кеноби
13

Я думаю, что у этого потока есть другой способ, более похожий на Rails: Scaffolding ActiveRecord: два столбца с одинаковым типом данных

В миграции:

t.belongs_to: transferrable_as

t.belongs_to: same_as

зеркало
источник
1
но как база данных узнает, с каким внешним ключом связать таблицу? Я пытаюсь это сделать с базой данных Postgres, и это дает мне ошибку, PG::UndefinedTable: ERRORкогда пытается добавить ограничение внешнего ключа в таблицу, которой не существует.
Тоби 1 Кеноби
В случае , если кто - то интересно, belongs_toэто просто псевдоним , чтобы referencesи поэтому имеет точно такую же функциональность.
Джейсон Светт
11

В качестве дополнительного ответа на этот вопрос - Модель должна иметь следующую строку для завершения ассоциации:

    belongs_to :transferrable_as, class_name: "Course"
    belongs_to :same_as, class_name: "Course"
Диего Диас де Беренгер
источник
3

Я не думаю, что referencesпримет этот :asвариант, но вы можете создавать свои столбцы вручную ...

create_table :courses do |t| 
  t.string  :name 
  t.integer :course1_id
  t.integer :course2_id 
  t.timestamps 
end 
Джу Ногейра
источник