91

Tengo dos modelos restaurant y user que deseo realizar una relación has_and_belongs_to_many.Rails has_and_belongs_to_many migration

que ya han entrado en los archivos de modelos y añadió la has_and_belongs_to_many :restaurants y has_and_belongs_to_many :users

Asumo en este punto que debería ser capaz de hacer algo así con Rails 3:

rails generate migration .... 

pero todo lo que tengo intentado parece fallar. Estoy seguro de que esto es algo realmente simple. Soy nuevo en los rieles, así que todavía estoy aprendiendo.

Respuesta

193

es necesario agregar una tabla de unión separada con sólo una restaurant_id y user_id (sin clave primaria), en orden alfabético .

Primero ejecute sus migraciones, luego edite el archivo de migración generado.

Rails 3

rails g migration create_restaurants_users_table 

Carriles 4:

rails g migration create_restaurants_users 

Rieles 5

rails g migration CreateJoinTableRestaurantUser restaurants users 

Desde el docs:

También hay un generador que producirá unir tablas, si joinTable es parte del nombre:


Su archivo de migración (nótese el :id => false; que es lo que impide la creación de una clave principal):

Rails 3

class CreateRestaurantsUsers < ActiveRecord::Migration 
    def self.up 
    create_table :restaurants_users, :id => false do |t| 
     t.references :restaurant 
     t.references :user 
    end 
    add_index :restaurants_users, [:restaurant_id, :user_id] 
    add_index :restaurants_users, :user_id 
    end 

    def self.down 
    drop_table :restaurants_users 
    end 
end 

Carriles 4

class CreateRestaurantsUsers < ActiveRecord::Migration 
    def change 
    create_table :restaurants_users, id: false do |t| 
     t.belongs_to :restaurant 
     t.belongs_to :user 
    end 
    end 
end 

t.belongs_to creará automáticamente los índices necesarios. def change detectará automáticamente una migración hacia adelante o hacia atrás, sin necesidad de subir/bajar.

rieles 5

create_join_table :restaurants, :users do |t| 
    t.index [:restaurant_id, :user_id] 
end 

Nota: También hay una opción para un nombre de tabla personalizada que se puede pasar como parámetro a create_join_table llamada table_name.Desde el docs

Por defecto, el nombre de la tabla de unión proviene de la unión de los dos primeros argumentos proporcionados a create_join_table, en orden alfabético orden. Para personalizar el nombre de la tabla, proporcionar una: nombre_tabla opción:

+0

gracias esa solución funcionó perfectamente para mí. Cometí un simple error al usar este método, probé un rake db: migrate después del comando rails y no generó la tabla. Tuve que hacer un rake db: rollback, luego editar el archivo y luego rake db: migrar pero todo funciona ahora. – dbslone

+6

@Dex: solo por curiosidad, ¿podría explicar por qué está utilizando un segundo índice compuesto, definido con orden de columnas invertidas? Tenía la impresión de que el orden de las columnas no importaba. No soy DBA, solo quiero ampliar mi propio entendimiento. ¡Gracias! – plainjimbo

+9

@Jimbo No lo necesita así, realmente depende de sus consultas. Los índices se leen de izquierda a derecha, por lo que el primero será más rápido si está buscando 'restaurant_id'. El segundo ayudará si está buscando 'user_id'. Si está buscando en ambos, creo que la base de datos sería lo suficientemente inteligente como para necesitar una sola. Así que supongo que el segundo no necesita ser compuesto. Esto fue más que un simple ejemplo. Sin embargo, esta era una pregunta de Rails, por lo que publicar en la sección DB arrojaría una respuesta más completa. – Dex

6

Para las relaciones HABTM, es necesario crear una tabla de unión. Solo hay una tabla de unión y esa tabla no debe tener una columna de identificación. Prueba esta migración

def self.up 
    create_table :restaurants_users, :id => false do |t| 
    t.integer :restaurant_id 
    t.integer :user_id 
    end 
end 

def self.down 
    drop_table :restaurants_users 
end 

Debe comprobar this relationship rails guide tutorials

+0

No creo que necesite un modelo y no veo nada en el enlace sobre la necesidad de un modelo para una relación HABTM. –

+1

Para agilizar las consultas generadas, agregue índices a los campos de id. –

24

Al crear la tabla de unión, prestar especial atención a la exigencia de que las dos tablas necesitan ser enumerados en orden alfabético en el nombre de la migración/clase. Esto puede morderlo fácilmente si los nombres de sus modelos son similares, p. "abc" y "abb". Si se va a ejecutar

rails g migration create_abc_abb_table 

Sus relaciones se no funciona como se espera. Debe utilizar

rails g migration create_abb_abc_table 

lugar.

+0

¿Qué es lo primero? foo o foo_bar? –

+1

@BSeven Me gustaría ir con lo que unix te diga. – shacker

+0

Se ejecutó en una consola de rieles: ["foo_bar", "foo", "foo bar"]. Sort # => ["foo", "foo bar", "foo_bar"] El género Unix aparece de la misma manera. – Shadoath

23

Las respuestas aquí son bastante anticuadas. A partir de Rails 4.0.2, sus migraciones hacen uso de create_join_table.

Para crear la migración, ejecute:

rails g migration CreateJoinTableRestaurantsUsers restaurant user 

Esto generará el siguiente:

class CreateJoinTableRestaurantsUsers < ActiveRecord::Migration 
    def change 
    create_join_table :restaurants, :users do |t| 
     # t.index [:restaurant_id, :user_id] 
     # t.index [:user_id, :restaurant_id] 
    end 
    end 
end 

Si desea indexar estas columnas, elimine las líneas respectivas y ya está bueno para ir !

Cuestiones relacionadas