Migrazione di Rails per la tabella di join has_and_belongs_to_many


Risposte:


228

Dove:

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :students
end

e

class Student < ActiveRecord::Base
  has_and_belongs_to_many :teachers
end

per binari 4:

rails generate migration CreateJoinTableStudentTeacher student teacher

per binari 3:

rails generate migration students_teachers student_id:integer teacher_id:integer

per binari <3

script/generate migration students_teachers student_id:integer teacher_id:integer

(nota che il nome della tabella elenca entrambe le tabelle di join in ordine alfabetico)

e quindi solo per rails 3 e inferiori, è necessario modificare la migrazione generata in modo che non venga creato un campo id:

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

16
Questa è l'unica risposta che risponde effettivamente alla domanda.
pingu

8
@pingu: tranne per il fatto che non funziona, almeno in Rails 3.2. Il file di migrazione generato è vuoto.
hoffmanc

7
Works for Rails 4.
Felipe Zavan

2
@hoffmanc Genererà un file di migrazione vuoto se non si specifica alcun campo. Devi specificare i campi se vuoi che Rails li aggiunga automaticamente al file di migrazione.
Andrew

1
ciao, ci sto provando rails generate migration CreateJoinTableTeacherStudent teacher studentinvece rails generate migration CreateJoinTableStudentTeacher student teacher, è lo stesso? S (tudent) deve prima di T (eacher)?
zx1986

138

Una has_and_belongs_to_manytabella deve corrispondere a questo formato. Presumo che i due modelli a cui unirsi has_and_belongs_to_manysiano già nel DB: applese 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)

Se usi l' :unique => trueindice, dovresti (in rails3) passare :uniq => truea has_and_belongs_to_many.

Ulteriori informazioni: Rails Docs

AGGIORNATO 2010-12-13 L'ho aggiornato per rimuovere id e timestamp ... Fondamentalmente MattDiPasqualee nunopoloniasono corretti: non deve esserci un id e non devono esserci timestamp o rails non permetteranno has_and_belongs_to_manydi funzionare.


6
In realtà, una tabella di join dovrebbe avere solo le due colonne di riferimenti e non ha colonne id o timestamp. Ecco un esempio migliore di una migrazione has_and_belongs_to_many dal collegamento che hai fornito. Sto cercando un modo per farlo dalla riga di comando con script/generate migration...
ma11hew28

Bene, non deve avere i timestamp; L'ho contrassegnato come facoltativo nel mio esempio. Tuttavia, consiglierei di aggiungere l'id. Ci sono casi in cui l'ID o il timestamp possono essere utili. Ma consiglio vivamente l'ID.
docwhat

Ok. Qual è un caso in cui l'ID sarebbe utile?
ma11hew28

Un esempio è se la relazione è abbastanza importante da avere una visione. Può anche essere utilizzato per velocizzare l'accesso ai database passando il relationship.id invece di cercarlo ripetutamente. Inoltre semplifica la risoluzione dei problemi del database. Soprattutto se gli ID delle altre colonne sono molto alti. È più facile ricordare id: 12345 invece di id: 54321-id: 67890 - Ma detto questo, se la tabella diventa davvero grande, potresti voler risparmiare spazio non allocando un altro ID per ogni relazione.
docwhat

2
Non credo che l'indice a più colonne sia la soluzione giusta per questo. Funzionerà per le query per mele particolari per trovare le arance correlate ma non il contrario. Due indici a colonna singola consentirebbero di interrogare in modo efficiente entrambe le direzioni, possibilmente con una piccola perdita per i controlli di esistenza di una particolare combinazione di mela e arancia).
Joseph Lord,

14

È necessario denominare la tabella con i nomi dei 2 modelli che si desidera collegare in ordine alfabetico e inserire i due ID modello nella tabella. Quindi connetti ogni modello tra loro creando le associazioni nel modello.

Ecco un esempio:

# 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

Ma questo non è molto flessibile e dovresti pensare di usare has_many: through


6

La risposta in alto mostra un indice composito che non credo verrà utilizzato per cercare le mele dalle arance.

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)

Ho trovato utile la risposta su cui si basa "The Doctor What" e certamente lo è anche la discussione.


4

In rails 4, puoi un utilizzo semplice

create_join_table: table1s,: table2s

è tutto.

Attenzione: è necessario offordinare table1, table2 con caratteri alfanumerici.


questa è una buona soluzione aggiornata. Nota, la tabella di join non è accessibile come modello, ma tramite le relazioni has_and_belongs_to_many impostate su entrambe le tabelle unite.
Siti web personalizzati

1

Mi piace fare:

rails g migration CreateJoinedTable model1:references model2:references. In questo modo ottengo una migrazione simile a questa:

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

Mi piace avere indice su queste colonne perché spesso farò ricerche utilizzando queste colonne.


add_foreign_keyfallirà se inserito nella stessa migrazione di quella che ha creato le tabelle.
Adib Saad
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.