2010-10-22 13 views
11

J'ai deux tables avec une relation plusieurs à plusieurs que j'utilise has_and_belongs_to_many pour définir l'association.Créer une table de jointure sans clé primaire

class Foo < ActiveRecord::Base 
    ... 
    has_and_belongs_to_many :bar 
    ... 
end 

class Bar < ActiveRecord::Base 
    ... 
    has_and_belongs_to_many :foo 
    ... 
end 

J'ai aussi la classe définie pour représenter la table de jointure

class BarFoo < ActiveRecord::Base 
    ... 
    belongs_to :foo 
    belongs_to :bar 
    ... 
end 

Quand je lance rake db: graines, j'obtiens l'erreur suivante:

Primary key is not allowed in a has_and_belongs_to_many join table (bar_foo) 

Si je modifie la base de données et supprimez le champ de clé primaire (ID) de la table bar_foo, puis réexécutez rake db: seed tout fonctionne comme vous le souhaitez.

Compte tenu de ce qui précède, quel est le moyen préféré de créer des tables jointes dans des rails sans clé primaire? J'ai également essayé d'utiliser "has_many: bars,: through =>: foo" et vice versa mais j'ai reçu un message d'erreur quelque chose comme "méthode non définie 'klass' pour nil: NilClass".

Répondre

4

Si vous souhaitez utiliser une association HABTM, vous ne devez pas créer de modèle pour elle - juste une table bars_foos avec bar_id et foo_id colonnes entières.

Si vous avez besoin du modèle entre (par exemple, si vous souhaitez garder une trace de created_at ou d'autres attributs de la relation), vous pouvez ajouter un modèle supplémentaire, par ex. Barred et vous auriez:

class Foo < ActiveRecord::Base 
    ... 
    has_many :bars, :through => :barred 
    ... 
end 

class Bar < ActiveRecord::Base 
    ... 
    has_many :foos, :through => :barred 
    ... 
end 

class Barred < ActiveRecord::Base 
    has_many :bars 
    has_many :foos 
end 
+0

Matt, merci pour la réponse. Je suis relativement nouveau à RoR alors quel est le moyen préféré de créer une table sans fichiers de modèles correspondants? Est-ce que cela serait fait en générant un fichier de migration et en utilisant create_table pour définir la table avec les deux attributs bar_id et foo_id? – Keith

+0

Voici une bonne réponse: [Dois-je créer manuellement une migration pour une table de jointure HABTM?] (Http://stackoverflow.com/questions/564306/do-i-need-to-manually-create -a-migration-pour-habtm-join-table) – Matt

22

Oui, clé primaire n'est pas autorisé pour has_and_belongs_to_many.

Vous avez 2 façons de résoudre ce:

Retirez la clé primaire sur la table. Dans votre classe de migration:

create_table :bar_foo, :id => false do |t| 
    t.integer :bar_id 
    t.integer :foo_id 
end 

En dehors de cela, vous devrez supprimer le fichier bar_foo.rb de app/models et également supprimer tous les fichiers de fixation et d'essai qui aurait pu être générés. Une bonne idée est d'appeler le script/destroy (ou rails destroy) pour détruire les fichiers et ensuite régénérer la migration.

Ou convertir à has_many :through

class Foo < ActiveRecord::Base 
    ... 
    has_many :bar_foos 
    has_many :bars, :through => :bar_foos 
    ... 
end 

class Bar < ActiveRecord::Base 
    ... 
    has_many :bar_foos 
    has_many :foos, :through => :bar_foos 
    ... 
end 

class BarFoo < ActiveRecord::Base 
    ... 
    belongs_to :foo 
    belongs_to :bar 
    ... 
end 
3

Vous n'avez pas besoin du modèle

class BarFoo < ActiveRecord::Base 
    ... 
    belongs_to :foo 
    belongs_to :bar 
    ... 
end 

l'association has_and_belongs_to_many recherchera une table appelée bar_foo dans votre base de données ce que vous devez faire est de générer un migration pour créer cette table.

rails génèrent la migration add_table_bar_foo_for_association

vous modifier votre migration et il devrait maintenant votre association comme celui-ci

class AddTableBarFooForAssociation < ActiveRecord::Migration 
    def up 
    create_table :bar_foo, :id => false do |t| 
     t.references :bar 
     t.references :foo 
    end 
    end 

    def down 
    drop_table :bar_foo 
    end 
end 

devrait fonctionner et aussi si vous avez besoin de l'association d'avoir des attributs supplémentaires sur le joindre à vous peut utiliser la méthode has_many :through et créer un modèle associé à cela.