Міграція рейків для таблиці приєднання has_and_belongs_to_many


Відповіді:


228

Де:

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :students
end

і

class Student < ActiveRecord::Base
  has_and_belongs_to_many :teachers
end

для рейок 4:

rails generate migration CreateJoinTableStudentTeacher student teacher

для рейок 3:

rails generate migration students_teachers student_id:integer teacher_id:integer

для рейок <3

script/generate migration students_teachers student_id:integer teacher_id:integer

(зауважте, що в назви таблиці перераховані обидві таблиці приєднання в алфавітному порядку)

а потім лише для рейок 3 і нижче потрібно відредагувати створену міграцію, щоб не було створено поле id:

create_table :students_teachers, :id => false do |t|

16
Це єдина відповідь, яка фактично відповідає на питання.
pingu

8
@pingu: за винятком того, що він не працює, принаймні в Rails 3.2. Згенерований файл міграції порожній.
hoffmanc

7
Працює на рейках 4.
Феліпе Заван

2
@hoffmanc Він створить порожній файл міграції, якщо не вказати жодні поля. Потрібно вказати поля, якщо ви хочете, щоб Rails автоматично додав їх у файл міграції.
Андрій

1
привіт, я намагаюся rails generate migration CreateJoinTableTeacherStudent teacher studentзамість цього rails generate migration CreateJoinTableStudentTeacher student teacher, це те саме? Чи потрібен S (тюдент) перед T (ечер)?
zx1986,

138

has_and_belongs_to_manyТаблиця повинна відповідати цьому формату. Я припускаю, що дві моделі, до яких слід приєднатися has_and_belongs_to_many, вже є в БД: applesі oranges:

create_table :apples_oranges, :id => false do |t|
  t.references :apple, :null => false
  t.references :orange, :null => false
end

# Adding the index can massively speed up join tables. Don't use the
# unique if you allow duplicates.
add_index(:apples_oranges, [:apple_id, :orange_id], :unique => true)

Якщо ви користуєтесь :unique => trueіндексом, то вам слід (у рейках3) перейти :uniq => trueдо has_and_belongs_to_many.

Більше інформації: Rails Docs

ОНОВЛЕНО 2010-12-13 Я оновив його, щоб видалити ідентифікатор та часові позначки ... В основному MattDiPasqualeі nunopoloniaправильно: ідентифікатор не повинен бути і не повинно бути часових позначок або рейки не дозволять has_and_belongs_to_manyпрацювати.


6
Насправді таблиця приєднання повинна містити лише два стовпці посилань і не мати стовпців ідентифікатора чи часових позначок. Ось кращий приклад міграції has_and_belongs_to_many із наведеного вами посилання. Я шукаю спосіб зробити це з командного рядка з script/generate migration...
ma11hew28

Ну, це не обов’язково мати часові позначки; Я вказав це як необов’язковий у своєму прикладі. Я б рекомендував додати ідентифікатор. Бувають випадки, коли може бути корисним або ідентифікатор, або позначка часу. Але я настійно рекомендую посвідчення особи.
docwhat

Гаразд. Який випадок, коли ідентифікатор буде корисним?
ma11hew28

Один із прикладів - якщо стосунки є досить важливими, щоб мати перегляд. Він також може бути використаний для прискорення доступу до баз даних, проходячи навколо Relations.id, а не повторюючи його. Це також полегшує усунення несправностей із базою даних. Особливо, якщо ідентифікатор інших стовпців дійсно високий. Простіше запам’ятати id: 12345 замість id: 54321-id: 67890 - Але якщо говорити, якщо таблиця стає дійсно великою, то, можливо, ви захочете зберегти простір, не виділяючи іншого ідентифікатора для кожного відносини.
docwhat

2
Я не думаю, що індекс багатоколінок є правильним рішенням для цього. Він буде працювати над запитами для конкретних яблук, щоб знайти пов'язані апельсини, але не навпаки. Два індекси одного стовпця дозволять ефективно запитувати обидва напрямки, можливо, з невеликою втратою для перевірки існування певного яблучно-помаранчевого поєднання).
Йосип Лорд

14

Ви повинні назвати таблицю іменами двох моделей, які ви хочете з'єднати за алфавітом, і помістити два ідентифікатори моделі в таблицю. Потім з'єднайте кожну модель між собою, створюючи асоціації в моделі.

Ось приклад:

# in migration
def self.up
  create_table 'categories_products', :id => false do |t|
    t.column :category_id, :integer
    t.column :product_id, :integer
  end
end

# models/product.rb
has_and_belongs_to_many :categories

# models/category.rb
has_and_belongs_to_many :products

Але це не дуже гнучко, і вам варто подумати про використання has_many: through


6

У верхній відповіді показаний складений індекс, який, я не вірю, буде використаний для пошуку яблук з апельсинів.

create_table :apples_oranges, :id => false do |t|
  t.references :apple, :null => false
  t.references :orange, :null => false
end

# Adding the index can massively speed up join tables.
# This enforces uniqueness and speeds up apple->oranges lookups.
add_index(:apples_oranges, [:apple_id, :orange_id], :unique => true)
# This speeds up orange->apple lookups
add_index(:apples_oranges, :orange_id)

Я знайшов відповідь, на якій ґрунтується "Доктор Що", корисний і обговорення, безумовно, теж.


4

У рейках 4 можна просто користуватися

create_join_table: table1s,: table2s

це все.

Застереження: ви повинні мати таблицю forford1, table2 з буквено-цифровими.


це хороше сучасне рішення. Зауважте, таблиця приєднання доступна не як модель, але через співвідношення has_and_belongs_to_many, які встановлені на обох об'єднаних таблицях.
Налаштовані веб-сайти

1

Мені подобається робити:

rails g migration CreateJoinedTable model1:references model2:references. Таким чином я отримую міграцію, яка виглядає приблизно так:

class CreateJoinedTable < ActiveRecord::Migration
  def change
    create_table :joined_tables do |t|
      t.references :trip, index: true
      t.references :category, index: true
    end
    add_foreign_key :joined_tables, :trips
    add_foreign_key :joined_tables, :categories
  end
end

Мені подобається, що в цих стовпцях є індекс, тому що я часто роблю пошук за допомогою цих стовпців.


add_foreign_keyне вдасться, якщо розмістити їх у тій же міграції, що і та, що створила таблиці.
Адіб Саад
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.