Rails hat_und_belongs_to_many Migration

119

Ich habe zwei Modelle restaurantund usermöchte eine Beziehung zwischen has_and_belongs_to_many durchführen.

Ich habe bereits in den Modelldateien gegangen und hat die has_and_belongs_to_many :restaurantsundhas_and_belongs_to_many :users

Ich gehe an dieser Stelle davon aus, dass ich in der Lage sein sollte, so etwas wie mit Rails 3 zu machen:

rails generate migration ....

aber alles, was ich versucht habe, scheint zu scheitern. Ich bin mir sicher, dass dies etwas wirklich Einfaches ist. Ich bin neu in Schienen, also lerne ich noch.

dbslone
quelle

Antworten:

259

Sie müssen eine separate Verknüpfungstabelle mit nur einem restaurant_idund user_id(kein Primärschlüssel) in alphabetischer Reihenfolge hinzufügen .

Führen Sie zuerst Ihre Migrationen aus und bearbeiten Sie dann die generierte Migrationsdatei.

Schienen 3

rails g migration create_restaurants_users_table

Schienen 4 :

rails g migration create_restaurants_users

Schienen 5

rails g migration CreateJoinTableRestaurantUser restaurants users

Aus den Dokumenten :

Es gibt auch einen Generator, der Join-Tabellen erzeugt, wenn JoinTable Teil des Namens ist:


Ihre Migrationsdatei (beachten :id => falseSie Folgendes: Sie verhindert die Erstellung eines Primärschlüssels):

Schienen 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

Schienen 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_toerstellt automatisch die erforderlichen Indizes. def changeerkennt automatisch eine Vorwärts- oder Rückwärtsmigration, ohne dass ein Auf / Ab erforderlich ist.

Schienen 5

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

Hinweis: Es gibt auch eine Option für einen benutzerdefinierten Tabellennamen, der als Parameter an create_join_table übergeben werden kann table_name. Aus den Dokumenten

Standardmäßig ergibt sich der Name der Verknüpfungstabelle aus der Vereinigung der ersten beiden Argumente für create_join_table in alphabetischer Reihenfolge. Geben Sie zum Anpassen des Tabellennamens die Option: table_name an:

Dex
quelle
7
@Dex - Können Sie aus Neugier erklären, warum Sie einen zweiten zusammengesetzten Index verwenden, der mit umgekehrter Spaltenreihenfolge definiert ist? Ich hatte den Eindruck, dass die Spaltenreihenfolge keine Rolle spielte. Ich bin kein DBA, möchte nur mein eigenes Verständnis fördern. Vielen Dank!
Plainjimbo
10
@ Jimbo Du brauchst es nicht so, es hängt wirklich von deinen Fragen ab. Die Indizes werden von links nach rechts gelesen, sodass der erste Index am schnellsten ist, wenn Sie weiter suchen restaurant_id. Die zweite hilft, wenn Sie weiter suchen user_id. Wenn Sie nach beiden suchen, würde ich denken, dass die Datenbank intelligent genug ist, um nur eine zu benötigen. Ich denke, der zweite muss nicht wirklich zusammengesetzt werden. Dies war eher nur ein Beispiel. Dies war jedoch eine Rails-Frage, sodass das Posten im DB-Bereich eine vollständigere Antwort liefern würde.
Dex
3
Der zweite Index weist eine gewisse Redundanz auf. Solange Sie sowohl restaurant_id als auch user_id abfragen, spielt die Reihenfolge in Ihrem SQL keine Rolle, und der erste Index wird verwendet. Es wird auch verwendet, wenn Sie nur auf restaurant_id abfragen. Der zweite Index muss nur aktiviert sein: user_id und wird in Fällen verwendet, in denen Sie nur user_id abfragen (bei denen der erste Index aufgrund der Reihenfolge seiner Schlüssel nicht hilfreich ist).
Yardboy
13
In Schienen 4 muss die Migration am Ende rails g migration create_restaurants_usersohne Tabelle sein .
Fa11enAngel
6
Sie können auch Rails g Migration verwenden. CreateJoinTableRestaurantUser Restaurantbenutzer. Lesen Sie guide.rubyonrails.org/migrations.html#creating-a-join-table
eKek0
36

Die Antworten hier sind ziemlich veraltet. Ab Rails 4.0.2 werden Ihre Migrationen verwendet create_join_table.

Führen Sie zum Erstellen der Migration Folgendes aus:

rails g migration CreateJoinTableRestaurantsUsers restaurant user

Dadurch wird Folgendes generiert:

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

Wenn Sie diese Spalten indizieren möchten, kommentieren Sie die entsprechenden Zeilen aus und los geht's!

Jan Klimo
quelle
2
Im Allgemeinen würde ich eine der Indexzeilen auskommentieren und ergänzen unique: true. Dadurch wird verhindert, dass doppelte Beziehungen erstellt werden.
Toby 1 Kenobi
26

Beachten Sie beim Erstellen der Verknüpfungstabelle sorgfältig die Anforderung, dass die beiden Tabellen in alphabetischer Reihenfolge im Migrationsnamen / der Migrationsklasse aufgeführt sein müssen . Dies kann Sie leicht beißen, wenn Ihre Modellnamen ähnlich sind, z. B. "abc" und "abb". Wenn du rennen würdest

rails g migration create_abc_abb_table

Ihre Beziehungen werden nicht wie erwartet funktionieren. Sie müssen verwenden

rails g migration create_abb_abc_table

stattdessen.

Shacker
quelle
1
Welches kommt zuerst? foo oder foo_bar?
B Sieben
1
Lief in einer Rails-Konsole: ["foo_bar", "foo", "foo bar"]. Sort # => ["foo", "foo bar", "foo_bar"] Die Unix-Sortierung wird gleich angezeigt.
Shadoath
6

Für HABTM-Beziehungen müssen Sie eine Verknüpfungstabelle erstellen. Es gibt nur eine Join-Tabelle und diese Tabelle sollte keine ID-Spalte haben. Versuchen Sie diese 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

Sie müssen diese Tutorials für Beziehungsschienen überprüfen

Mohit Jain
quelle
Ich glaube nicht, dass Sie ein Modell benötigen, und ich sehe im Link nichts darüber, dass Sie ein Modell für eine HABTM-Beziehung benötigen.
B sieben
1
Fügen Sie den ID-Feldern Indizes hinzu, um die generierten Abfragen zu beschleunigen.
Martin Röbert