Миграция Rails для таблицы соединений 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|
dangerousdave
источник
16
Это единственный ответ, который действительно отвечает на вопрос.
pingu
8
@pingu: за исключением того, что это не работает, по крайней мере, в Rails 3.2. Созданный файл миграции пуст.
hoffmanc 07
7
Работает для Rails 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индексе, тогда вы должны (в rails3) перейти :uniq => trueк has_and_belongs_to_many.

Дополнительная информация: Rails Docs

ОБНОВЛЕНО 13 декабря 2010 г. Я обновил его, чтобы удалить идентификатор и временные метки ... В основном MattDiPasqualeи nunopoloniaони верны: не должно быть идентификатора и не должно быть временных меток, иначе рельсы не позволят has_and_belongs_to_manyработать.

docwhat
источник
6
Фактически, объединенная таблица должна иметь только два столбца ссылок и не иметь столбцов id или timestamp. Вот лучший пример миграции has_and_belongs_to_many из предоставленной вами ссылки. Я ищу способ сделать это из командной строки с помощью script/generate migration...
ma11hew28 07
Ну, это не обязательно должно иметь временные метки; В моем примере я пометил это как необязательное. Однако я бы порекомендовал добавить идентификатор. Бывают случаи, когда может быть полезен либо идентификатор, либо временная метка. Но я настоятельно рекомендую ID.
docwhat
Хорошо. В каком случае ID будет полезен?
ma11hew28
Один пример: если отношения достаточно важны, чтобы иметь представление. Его также можно использовать для ускорения доступа к базам данных путем передачи файла Relationship.id вместо того, чтобы искать его повторно. Это также упрощает поиск и устранение неисправностей в базе данных. Особенно, если идентификаторы других столбцов действительно высоки. Легче запомнить id: 12345 вместо id: 54321-id: 67890 - но при этом, если таблица становится действительно большой, вы можете сэкономить место, не выделяя другой идентификатор для каждой связи.
docwhat 05
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

nunopolonia
источник
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

это все.

Внимание: вы должны записывать table1, table2 буквенно-цифровыми значениями.

zw963
источник
это хорошее современное решение. Обратите внимание, что объединенная таблица недоступна в качестве модели, а доступна через отношения 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

Мне нравится индексировать эти столбцы, потому что я часто выполняю поиск, используя эти столбцы.

Jwan622
источник
add_foreign_keyзавершится ошибкой, если поместить ее в ту же миграцию, что и та, которая создавала таблицы.
Адиб Саад