Migracja szyn do tabeli łączenia has_and_belongs_to_many

Odpowiedzi:

228

Gdzie:

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :students
end

i

class Student < ActiveRecord::Base
  has_and_belongs_to_many :teachers
end

dla szyn 4:

rails generate migration CreateJoinTableStudentTeacher student teacher

dla szyn 3:

rails generate migration students_teachers student_id:integer teacher_id:integer

dla szyn <3

script/generate migration students_teachers student_id:integer teacher_id:integer

(zwróć uwagę, że nazwa tabeli zawiera obie tabele łączenia w kolejności alfabetycznej)

a następnie tylko dla szyn 3 i niższych, musisz edytować wygenerowaną migrację, aby pole identyfikatora nie zostało utworzone:

create_table :students_teachers, :id => false do |t|
dangerousdave
źródło
16
To jedyna odpowiedź, która faktycznie odpowiada na to pytanie.
pingu
8
@pingu: poza tym, że nie działa, przynajmniej w Railsach 3.2. Wygenerowany plik migracji jest pusty.
hoffmanc
7
Works for Rails 4.
Felipe Zavan
2
@hoffmanc Wygeneruje pusty plik migracji, jeśli nie określisz żadnych pól. Musisz określić pola, jeśli chcesz, aby Railsy automatycznie dodawały je do pliku migracji.
Andrew
1
cześć, próbuję rails generate migration CreateJoinTableTeacherStudent teacher studentzamiast rails generate migration CreateJoinTableStudentTeacher student teacher, czy to to samo? Czy S (tudent) musi przed T (eacher)?
zx1986
138

has_and_belongs_to_manyStół musi pasować ten format. Zakładam, że dwa modele, które mają zostać połączone, has_and_belongs_to_manysą już w bazie danych: applesi 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)

Jeśli używasz :unique => trueindeksu, powinieneś (w rails3) przejść :uniq => truedo has_and_belongs_to_many.

Więcej informacji: Rails Docs

ZAKTUALIZOWANO 2010-12-13 Zaktualizowałem go, aby usunąć identyfikator i znaczniki czasu ... Zasadniczo MattDiPasqualei nunopoloniasą one poprawne: nie może być identyfikatora i nie może być znaczników czasu ani szyn, które nie pozwolą has_and_belongs_to_manydziałać.

docwhat
źródło
6
W rzeczywistości tabela łączenia powinna mieć tylko dwie kolumny odwołań i nie powinna mieć kolumn z identyfikatorami ani datownikami. Oto lepszy przykład migracji has_and_belongs_to_many z linku, który podałeś. Szukam sposobu na zrobienie tego z wiersza poleceń za pomocą script/generate migration...
ma11hew28,
Cóż, nie musi mieć sygnatur czasowych; Oznaczyłem to jako opcjonalne w moim przykładzie. Zalecałbym jednak dodanie identyfikatora. Istnieją przypadki, w których identyfikator lub znacznik czasu mogą być przydatne. Ale zdecydowanie polecam ID.
docwhat
Dobrze. W jakim przypadku identyfikator byłby przydatny?
ma11hew28
Jednym z przykładów jest sytuacja, w której związek jest na tyle ważny, że można go zobaczyć. Można go również użyć do przyspieszenia dostępu do baz danych, omijając plik Relations.id zamiast wielokrotnie go wyszukiwać. Ułatwia również rozwiązywanie problemów z bazą danych. Zwłaszcza jeśli identyfikatory innych kolumn są naprawdę wysokie. Łatwiej jest zapamiętać id: 12345 zamiast id: 54321-id: 67890 - Ale biorąc pod uwagę to, że jeśli tabela zrobi się naprawdę duża, możesz chcieć zaoszczędzić miejsce, nie przydzielając innego identyfikatora dla każdej relacji.
docwhat
2
Nie sądzę, aby indeks wielokolumnowy był w tym przypadku odpowiednim rozwiązaniem. Będzie działać w przypadku zapytań dotyczących konkretnych jabłek, aby znaleźć powiązane pomarańcze, ale nie na odwrót. Dwa indeksy jednokolumnowe umożliwiłyby efektywne odpytywanie w obu kierunkach, prawdopodobnie z niewielką stratą do sprawdzenia istnienia konkretnej kombinacji jabłka i pomarańczy).
Joseph Lord
14

Powinieneś nazwać tabelę nazwami 2 modeli, które chcesz połączyć w kolejności alfabetycznej i umieścić dwa identyfikatory modeli w tabeli. Następnie połącz każdy model ze sobą, tworząc w modelu skojarzenia.

Oto przykład:

# 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

Ale to nie jest zbyt elastyczne i powinieneś pomyśleć o użyciu has_many: through

nunopolonia
źródło
6

Górna odpowiedź pokazuje złożony indeks, który, jak sądzę, nie będzie używany do wyszukiwania jabłek z pomarańczy.

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)

Uznałem, że odpowiedź, na podstawie której jest to oparte na „Doktorze What”, jest użyteczna i dyskusja z pewnością również.

Joseph Lord
źródło
4

W szynach 4 można łatwo używać

create_join_table: table1s,: table2s

to wszystko.

Uwaga: tabelę1, tabelę2 należy wyłączyć alfanumerycznie.

zw963
źródło
jest to dobre, aktualne rozwiązanie. Należy zauważyć, że tabela łączenia nie jest dostępna jako model, ale za pośrednictwem relacji has_and_belongs_to_many, które są skonfigurowane w obu połączonych tabelach.
Witryny internetowe Taylored
1

Lubię robić:

rails g migration CreateJoinedTable model1:references model2:references. W ten sposób otrzymuję migrację, która wygląda następująco:

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

Lubię mieć indeksy w tych kolumnach, ponieważ często będę wyszukiwać za pomocą tych kolumn.

Jwan622
źródło
add_foreign_keyzakończy się niepowodzeniem, jeśli zostanie umieszczony w tej samej migracji, co ta, która utworzyła tabele.
Adib Saad