Has_and_belongs_to_many birleştirme tablosu için ray geçişi


Yanıtlar:


228

Nerede:

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :students
end

ve

class Student < ActiveRecord::Base
  has_and_belongs_to_many :teachers
end

raylar 4 için:

rails generate migration CreateJoinTableStudentTeacher student teacher

raylar 3 için:

rails generate migration students_teachers student_id:integer teacher_id:integer

raylar için <3

script/generate migration students_teachers student_id:integer teacher_id:integer

(tablo adının her iki birleştirme tablosunu alfabetik sırada listelediğine dikkat edin)

ve sonra yalnızca 3 ve altındaki raylar için, oluşturulan geçişinizi bir kimlik alanı oluşturulmayacak şekilde düzenlemeniz gerekir:

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

16
Soruyu gerçekten cevaplayan tek cevap budur.
pingu

8
@pingu: en azından Rails 3.2'de çalışmaması dışında. Oluşturulan taşıma dosyası boş.
hoffmanc

7
Rails 4 için çalışıyor.
Felipe Zavan

2
@hoffmanc Herhangi bir alan belirtmezseniz boş bir geçiş dosyası oluşturacaktır. Rails'in bunları otomatik olarak geçiş dosyasına eklemesini istiyorsanız alanları belirtmelisiniz.
Andrew

1
merhaba, rails generate migration CreateJoinTableTeacherStudent teacher studentbunun yerine deniyorum rails generate migration CreateJoinTableStudentTeacher student teacher, aynı mı? S (tudent) 'in T'den (herer) önce olması gerekir mi?
zx1986

138

Bir has_and_belongs_to_manytablo bu formatla eşleşmelidir. Birleştirilecek iki modelin has_and_belongs_to_manyzaten DB'de olduğunu varsayıyorum : applesve 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)

Eğer kullanırsanız :unique => trueendeksi, o zaman (raylar 3. olarak) geçmelidir :uniq => trueiçin has_and_belongs_to_many.

Daha fazla bilgi: Rails Docs

GÜNCELLENDİ 2010-12-13 Kimliği ve zaman damgalarını kaldıracak şekilde güncelledim ... Temelde MattDiPasqualeve nunopoloniadoğru: Bir kimlik olmamalı ve zaman damgaları olmamalı veya raylar has_and_belongs_to_manyçalışmasına izin vermiyor .


6
Aslında, bir birleştirme tablosu yalnızca iki referans sütununa sahip olmalı ve kimlik veya zaman damgası sütunlarına sahip olmamalıdır. İşte verdiğiniz bağlantıdan has_and_belongs_to_many geçişinin daha iyi bir örneği . Bunu komut satırından yapmanın bir yolunu arıyorum script/generate migration...
ma11hew28

Zaman damgalarına sahip olmak zorunda değil; Örneğimde isteğe bağlı olarak işaretledim. Yine de kimliği eklemenizi tavsiye ederim. Kimliğin veya zaman damgasının yararlı olabileceği durumlar vardır. Ama kimliği şiddetle tavsiye ederim.
docwhat

Tamam. Kimliğin yararlı olacağı bir durum nedir?
ma11hew28

Bir örnek, ilişkinin bir görüşe sahip olacak kadar önemli olup olmadığıdır. Ayrıca, art arda aramak yerine ilişkinin etrafından dolaşarak veritabanlarına erişimi hızlandırmak için de kullanılabilir. Ayrıca, veritabanında sorun gidermeyi kolaylaştırır. Özellikle diğer sütunların kimlikleri gerçekten yüksekse. İd: 54321-id: 67890 yerine id: 12345'i hatırlamak daha kolaydır - Ancak, eğer tablo gerçekten büyürse, her ilişki için başka bir kimlik ayırmayarak yerden tasarruf edebilmek isteyebilirsiniz.
docwhat

2
Bunun için çok sütunlu dizinin doğru çözüm olduğunu düşünmüyorum. İlgili portakalları bulmak için belirli elmalar için sorgular için çalışacak, ancak tersi olmayacaktır. İki tek sütun indeksi, muhtemelen belirli bir elma, portakal kombinasyonunun mevcudiyet kontrollerinde küçük bir kayıpla her iki yönün de verimli bir şekilde sorgulanmasına izin verecektir.
Joseph Lord

14

Tabloya, bağlanmak istediğiniz 2 modelin ismini alfabetik sırayla isimlendirmeli ve iki model kimliğini tabloya koymalısınız. Ardından, modeldeki ilişkilendirmeleri oluşturarak her modeli birbirine bağlayın.

İşte bir örnek:

# 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

Ancak bu çok esnek değildir ve has_many kullanmayı düşünmelisiniz: aracılığıyla


6

En üstteki cevap, portakallardan elma aramak için kullanılacağına inanmadığım bileşik bir indeksi gösteriyor.

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)

Bunun "The Doctor What" dan temel aldığı cevabı faydalı buldum ve tartışma kesinlikle çok faydalı.


4

Raylarda 4, basit kullanım yapabilirsiniz

create_join_table: table1s,: table2s

hepsi bu.

Dikkat: alfanümerik olan tablo1, tablo2'yi kullanmanız gerekir.


bu iyi bir güncel çözümdür. Birleştirme tablosuna bir model olarak erişilemeyeceğini, ancak her iki birleştirilmiş tabloda ayarlanan has_and_belongs_to_many ilişkileri aracılığıyla erişilebileceğini unutmayın.
Taylored Web Siteleri

1

Yapmayı seviyorum:

rails g migration CreateJoinedTable model1:references model2:references. Bu şekilde şuna benzeyen bir geçiş elde ederim:

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

Bu sütunlarda dizine sahip olmayı seviyorum çünkü sık sık bu sütunları kullanarak arama yapacağım.


add_foreign_key tabloları oluşturan ile aynı geçişe yerleştirilirse başarısız olur.
Adib Saad
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.