Migración de rieles para has_and_belongs_to_many join table

Respuestas:

228

Dónde:

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :students
end

y

class Student < ActiveRecord::Base
  has_and_belongs_to_many :teachers
end

para carriles 4:

rails generate migration CreateJoinTableStudentTeacher student teacher

para rieles 3:

rails generate migration students_teachers student_id:integer teacher_id:integer

para rieles <3

script/generate migration students_teachers student_id:integer teacher_id:integer

(tenga en cuenta que el nombre de la tabla enumera ambas tablas de unión en orden alfabético)

y luego solo para los rieles 3 e inferiores, debe editar su migración generada para que no se cree un campo de identificación:

create_table :students_teachers, :id => false do |t|
peligroso
fuente
16
Esta es la única respuesta que realmente responde la pregunta.
pingu
8
@pingu: excepto que no funciona, al menos en Rails 3.2. El archivo de migración generado está en blanco.
hoffmanc
77
Works for Rails 4.
Felipe Zavan
2
@hoffmanc Generará un archivo de migración vacío si no especifica ningún campo. Debe especificar los campos si desea que Rails los agregue automáticamente al archivo de migración.
Andrew
1
hola, estoy intentando en rails generate migration CreateJoinTableTeacherStudent teacher studentlugar de rails generate migration CreateJoinTableStudentTeacher student teacher, ¿es lo mismo? ¿S (tudent) necesita antes que T (eacher)?
zx1986
138

Una has_and_belongs_to_manytabla debe coincidir con este formato. Supongo que los dos modelos a los que se unirán has_and_belongs_to_manyya están en la base de datos: applesy 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)

Si usa el :unique => trueen el índice, entonces debería (en rails3) pasar :uniq => truea has_and_belongs_to_many.

Más información: Rails Docs

ACTUALIZADO 2010-12-13 Lo actualicé para eliminar la identificación y las marcas de tiempo ... Básicamente MattDiPasqualey nunopoloniason correctas: no debe haber una identificación y no debe haber marcas de tiempo o los rieles no permitirán has_and_belongs_to_manytrabajar.

docwhat
fuente
66
En realidad, una tabla de unión solo debe tener las dos columnas de referencias y no tiene columnas de identificación o marca de tiempo. Aquí hay un mejor ejemplo de una migración has_and_belongs_to_many desde el enlace que proporcionó. Estoy buscando una manera de hacerlo desde la línea de comando con script/generate migration...
ma11hew28
Bueno, no tiene que tener las marcas de tiempo; Lo marqué opcional en mi ejemplo. Sin embargo, recomendaría agregar la identificación. Hay casos en que la ID o la marca de tiempo pueden ser útiles. Pero recomiendo la identificación.
docwhat
Okay. ¿Cuál es un caso en el que la identificación sería útil?
ma11hew28
Un ejemplo es si la relación es lo suficientemente importante como para tener una vista. También se puede usar para acelerar el acceso a la base de datos al pasar la relación.id en lugar de buscarlo repetidamente. También facilita la resolución de problemas de la base de datos. Especialmente si los identificadores de las otras columnas son realmente altos. Es más fácil recordar id: 12345 en lugar de id: 54321-id: 67890 - Pero dicho esto, si la tabla se vuelve realmente grande, es posible que desee ahorrar espacio al no asignar otra identificación para cada relación.
docwhat
2
No creo que el índice de varias columnas sea la solución correcta para esto. Funcionará para consultas de manzanas particulares para encontrar las naranjas relacionadas, pero no al revés. Dos índices de una sola columna permitirían consultar eficientemente ambas direcciones, posiblemente con una pequeña pérdida en las comprobaciones de existencia de una combinación particular de manzana y naranja).
Joseph Lord
14

Debe asignar a la tabla los nombres de los 2 modelos que desea conectar por orden alfabético y colocar los dos identificadores de modelo en la tabla. Luego, conecte cada modelo entre sí creando las asociaciones en el modelo.

Aquí hay un ejemplo:

# 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

Pero esto no es muy flexible y debería pensar en usar has_many: through

nunopolonia
fuente
6

La respuesta principal muestra un índice compuesto que no creo que se utilizará para buscar manzanas de naranjas.

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)

Encontré que la respuesta en la que se basa 'The Doctor What' es útil y la discusión también lo es.

Joseph Lord
fuente
4

En los rieles 4, puede usar de manera simple

create_join_table: table1s,: table2s

esto es todo.

Precaución: debe ofrecerford table1, table2 con alfanumérico.

zw963
fuente
Esta es una buena solución actualizada. Tenga en cuenta que la tabla de unión no es accesible como modelo, sino a través de las relaciones has_and_belongs_to_many que se configuran en ambas tablas unidas.
Sitios web Taylored
1

Me gusta hacer:

rails g migration CreateJoinedTable model1:references model2:references. De esa manera obtengo una migración que se ve así:

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

Me gusta tener índice en estas columnas porque a menudo haré búsquedas usando estas columnas.

Jwan622
fuente
add_foreign_keyfallará si se coloca en la misma migración que la que creó las tablas.
Adib Saad