Migrasi rel untuk tabel gabungan has_and_belongs_to_many

Jawaban:

228

Dimana:

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :students
end

dan

class Student < ActiveRecord::Base
  has_and_belongs_to_many :teachers
end

untuk rel 4:

rails generate migration CreateJoinTableStudentTeacher student teacher

untuk rel 3:

rails generate migration students_teachers student_id:integer teacher_id:integer

untuk rel <3

script/generate migration students_teachers student_id:integer teacher_id:integer

(perhatikan nama tabel mencantumkan kedua tabel bergabung dalam urutan abjad)

dan kemudian hanya untuk rails 3 dan di bawahnya, Anda perlu mengedit migrasi yang Anda buat sehingga bidang id tidak dibuat:

create_table :students_teachers, :id => false do |t|
berbahayadave
sumber
16
Ini adalah satu-satunya jawaban yang benar-benar menjawab pertanyaan tersebut.
pingu
8
@pingu: kecuali itu tidak berhasil, setidaknya di Rails 3.2. File migrasi yang dibuat kosong.
hoffmanc
7
Bekerja untuk Rails 4.
Felipe Zavan
2
@hoffmanc Ini akan menghasilkan file migrasi kosong jika Anda tidak menentukan bidang apapun. Anda harus menentukan bidang jika Anda ingin Rails secara otomatis menambahkannya ke file migrasi.
Andrew
1
halo, aku mencoba rails generate migration CreateJoinTableTeacherStudent teacher studentbukan rails generate migration CreateJoinTableStudentTeacher student teacher, adalah bahwa sama? Apakah S (Tudent) perlu sebelum T (guru)?
zx1986
138

Sebuah has_and_belongs_to_manymeja harus sesuai format ini. Saya berasumsi dua model yang akan digabungkan has_and_belongs_to_manysudah ada di DB: applesdan 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)

Jika Anda menggunakan :unique => truedi indeks, maka Anda harus (di rails3) lolos :uniq => trueke has_and_belongs_to_many.

Informasi lebih lanjut: Rails Docs

UPDATED 2010-12-13 Saya telah memperbaruinya untuk menghapus id dan cap waktu ... Pada dasarnya MattDiPasqualedan nunopoloniabenar: Tidak boleh ada id dan tidak boleh ada cap waktu atau rel tidak akan memungkinkan has_and_belongs_to_manyuntuk bekerja.

docwhat
sumber
6
Sebenarnya, tabel gabungan seharusnya hanya memiliki dua kolom referensi dan tidak memiliki kolom id atau timestamp. Berikut adalah contoh migrasi has_and_belongs_to_many yang lebih baik dari tautan yang Anda berikan. Saya mencari cara untuk melakukannya dari baris perintah dengan script/generate migration...
ma11hew28
Yah, itu tidak harus memiliki cap waktu; Saya menandainya sebagai opsional dalam contoh saya. Saya akan merekomendasikan menambahkan id. Ada beberapa kasus di mana ID atau stempel waktu dapat berguna. Tapi saya sangat merekomendasikan ID.
docwhat
Baik. Apa kasus di mana ID akan berguna?
ma11hew28
Salah satu contohnya adalah jika hubungan cukup penting untuk memiliki pandangan. Ini juga dapat digunakan untuk mempercepat pengaksesan databas dengan melewati relationship.id alih-alih mencarinya berulang kali. Itu juga membuat pemecahan masalah database lebih mudah. Apalagi jika id kolom lain sangat tinggi. Lebih mudah untuk mengingat id: 12345 daripada id: 54321-id: 67890 - Namun demikian, jika tabel menjadi sangat besar maka Anda mungkin ingin dapat menghemat ruang dengan tidak mengalokasikan id lain untuk setiap hubungan.
docwhat
2
Saya tidak berpikir indeks multikolom adalah solusi yang tepat untuk ini. Ini akan bekerja untuk kueri apel tertentu untuk menemukan jeruk terkait tetapi tidak sebaliknya. Dua indeks kolom tunggal akan memungkinkan kedua arah ditanyakan secara efisien mungkin dengan kerugian kecil terhadap pemeriksaan keberadaan kombinasi apel, oranye tertentu).
Joseph Lord
14

Anda harus menamai tabel dengan nama 2 model yang ingin Anda hubungkan berdasarkan urutan abjad dan meletakkan kedua id model di tabel. Kemudian hubungkan setiap model satu sama lain membuat asosiasi dalam model.

Berikut contohnya:

# 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

Tetapi ini tidak terlalu fleksibel dan Anda harus berpikir untuk menggunakan has_many: through

nunopolonia
sumber
6

Jawaban teratas menunjukkan indeks komposit yang saya tidak percaya akan digunakan untuk mencari apel dari jeruk.

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)

Saya menemukan jawaban yang didasarkan pada 'The Doctor What' berguna dan diskusi yang pasti juga.

Joseph Lord
sumber
4

Di rel 4, Anda dapat menggunakan dengan mudah

create_join_table: table1s,: table2s

itu semua.

Perhatian: Anda harus keluar dari tabel1, tabel2 dengan alfanumerik.

zw963
sumber
ini adalah solusi terkini yang bagus. Catatan, tabel gabungan tidak dapat diakses sebagai model, tetapi melalui relasi has_and_belongs_to_many yang diatur pada kedua tabel yang digabungkan.
Situs Web Taylored
1

Saya suka melakukan:

rails g migration CreateJoinedTable model1:references model2:references. Dengan cara itu saya mendapatkan migrasi yang terlihat seperti ini:

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

Saya suka memiliki indeks pada kolom ini karena saya akan sering melakukan pencarian menggunakan kolom ini.

Jwan622
sumber
add_foreign_keyakan gagal jika ditempatkan dalam migrasi yang sama seperti yang membuat tabel.
Adib Saad