web-dev-qa-db-fra.com

Rails has_and_belongs_to_many migration

J'ai deux modèles restaurant et user que je souhaite effectuer une relation has_and_belongs_to_many.

Je suis déjà entré dans les fichiers de modèle et ajouté le has_and_belongs_to_many :restaurants et has_and_belongs_to_many :users

Je suppose qu'à ce stade je devrais pouvoir faire quelque chose comme avec Rails 3:

Rails generate migration ....

mais tout ce que j'ai essayé semble échouer. Je suis sûr que c'est quelque chose de très simple, je suis nouveau sur Rails, donc j'apprends encore.

113
dbslone

Vous devez ajouter une table de jointure séparée avec uniquement un restaurant_id et user_id (pas de clé primaire), dans ordre alphabétique .

Commencez par exécuter vos migrations, puis modifiez le fichier de migration généré.

Rails 3

Rails g migration create_restaurants_users_table

Rails 4 :

Rails g migration create_restaurants_users

Rails 5

Rails g migration CreateJoinTableRestaurantUser restaurants users

De la docs :

Il existe également un générateur qui produira des tables de jointure si JoinTable fait partie du nom:


Votre fichier de migration (notez le :id => false; c'est ce qui empêche la création d'une clé primaire):

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

Rails 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 créera automatiquement les index nécessaires. def change détectera automatiquement une migration en avant ou en arrière, pas besoin de monter/descendre.

Rails 5

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

Remarque: Il existe également une option pour un nom de table personnalisé pouvant être transmise en tant que paramètre à create_join_table appelée table_name. De la docs

Par défaut, le nom de la table de jointure provient de l'union des deux premiers arguments fournis à create_join_table, dans l'ordre alphabétique. Pour personnaliser le nom de la table, spécifiez une option: nom_table:

242
Dex

Les réponses ici sont assez datées. A partir de Rails 4.0.2, vos migrations utilisent create_join_table.

Pour créer la migration, exécutez:

Rails g migration CreateJoinTableRestaurantsUsers restaurant user

Cela générera les éléments suivants:

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 vous souhaitez indexer ces colonnes, décommentez les lignes respectives et vous êtes prêt à partir!

30
Jan Klimo

Lors de la création de la table de jointure, veillez à ce que les deux tables soient répertoriées dans l'ordre ordre alphabétique dans le nom/la classe de la migration. Cela peut facilement vous mordre si vos noms de modèle sont similaires, par exemple. "abc" et "abb". Si tu devais courir

Rails g migration create_abc_abb_table

Vos relations vont pas fonctionner comme prévu. Tu dois utiliser

Rails g migration create_abb_abc_table

au lieu.

24
shacker

Pour les relations HABTM, vous devez créer une table de jointure. Il n'y a qu'une table de jointure et cette table ne doit pas avoir de colonne id. Essayez cette migration.

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

Vous devez vérifier cette relation Rails)

6
Mohit Jain