2013-04-18 2 views
0

J'essaie de comprendre comment utiliser les relations ActiveRecord pour associer un modèle qui peut contenir plusieurs instances d'un autre modèle dans une rangée. Par exemple, avoir has_many: chiens dans un modèle, et belongs_to: chien dans l'autre signifie que dans un modèle, "dog_id" se référera à une instance de: chien. Cependant, je veux pouvoir avoir plusieurs instances de: chien dans mon modèle (has_many) lié, comme dog_id1, dog_id2, dog_id3, etc. Voir le code ci-dessous pour comprendre ce que je veux dire. Comment puis-je faire ceci?Utilisation des relations ActiveRecord pour contenir plusieurs instances d'un objet par ligne

Je les modèles suivants:

--tp.rb 
class Tp < ActiveRecord::Base 
    has_many :dogs 
    has_many :cats 
    has_many :stars 
    attr_accessible :dog_id1, :dog_id2, :dog_id3, :dog_id4, :cat_id1, :cat_id2, :cat_id3, :cat_id4, :star_id, :tp_id 
end 

--dog.rb 
class Dog < ActiveRecord:: 
    belongs_to :tp 
    attr_accessible :dog_id, :dog_name 
end 

--cat.rb 
class Cat < ActiveRecord::Base 
    belongs_to :tp 
    attr_accessible :cat_id, :cat_name 
end 

--star.rb 
class Star < ActiveRecord::Base 
    belongs_to :tp 
    attr_accessible :patient_id 
end 
+0

Avez-vous lu http://guides.rubyonrails.org/association_basics.html? –

+0

@AlexTeut oui j'ai – jamesdlivesinatree

Répondre

1

Je pense que vous avez votre belongs_to/has_many un peu en arrière.

belongs_to et has_many

Pour votre exemple,

class Tp < ActiveRecord::Base 
    has_many :dogs 
    has_many :cats 
    has_many :stars 
end 

Tp n'ont pas dog_id, cat_id ou star_id dans sa ligne de base de données. Lorsque vous définissez belongs_to dans les autres modèles,

class Dog < ActiveRecord::Base 
    belongs_to :tp 
end 

class Cat < ActiveRecord::Base 
    belongs_to :tp 
end 

class Star < ActiveRecord::Base 
    belongs_to :tp 
end 

Vous devez ajouter un tp_id à chaque modèle (tableau dogs, table cats et stars tableau).

Puis, appelant

tp = Tp.find(123) 

Tp avec Constate id égal à 123

SELECT * FROM tps WHERE id = 123; 

Et appeler

cats = tp.cats 
dogs = tp.dogs 
stars = tp.stars 

recherche tous les Cat, Dog et Star insta nces avec tp_id égal à 123

SELECT * FROM cats WHERE tp_id = 123; 
SELECT * FROM dogs WHERE tp_id = 123; 
SELECT * FROM stars WHERE tp_id = 123; 

Si vous avez besoin de vos Cat cas d'appartenir à de nombreux cas Tp et Tp cas d'avoir de nombreux Cat cas, alors vous devriez regarder Rails pour has_and_belongs_to_many ou has_many :through.

has_and_belongs_to_many

une relation has_and_belongs_to nécessiterait de nouvelles tables cats_tps, dogs_tps et stars_tps. Ces tables auraient un schéma de

cats_tps 
    cat_id 
    tp_id 
dogs_tps 
    dog_id 
    tp_id 
stars_tps 
    star_id 
    tp_id 

Puis dans vos modèles

class Tp < ActiveRecord::Base 
    has_and_belongs_to_many :dogs 
    has_and_belongs_to_many :cats 
    has_and_belongs_to_many :stars 
end 

class Dog < ActiveRecord::Base 
    has_and_belongs_to_many :tps 
end 

class Cat < ActiveRecord::Base 
    has_and_belongs_to_many :tps 
end 

class Star < ActiveRecord::Base 
    has_and_belongs_to_many :tps 
end 

Maintenant, la course

tp = Tp.find(123) 
cats = tp.cats 

Génère le SQL

SELECT "cats".* FROM "cats" INNER JOIN "cats_tps" ON "cats"."id" = "cats_tps"."cat_id" WHERE "cats_tps"."tp_id" = 123; 

Quelle est essentialy la requête (Obtenez-moi une liste o f tous les cat_ids qui appartiennent à Tp 123) et puis (obtenez-moi tous les chats qui correspondent à ces identifiants de chat).

Génération du tableau cats_tps jointure peut se faire avec une migration comme

class CreateCatsTps < ActiveRecord::Migration 
    def change 
    create_table :cats_tps, :id => false do |t| 
     t.belongs_to :cat 
     t.belongs_to :tp 
    end 
    end 
end 

Cela fonctionne très bien pour les jointures simples, mais vous voudrez peut-être regarder dans has_many :through. C'est parce que la table cats_tps ne détient aucune information sur quand ou pourquoi ce Cat appartient à un Tp ou ce Tp appartient au Cat. De même, si vous ajoutez des modèles Bird, Horse, Frog et Snake, vous devrez créer les tableaux birds_tps, horses_tps, frogs_tps et snakes_tps. Yuck.

has_many: par

Pour créer une relation has_many :through, vous créez un nouveau modèle qui est logique sémantiquement qui relie un Tp à un Cat. Par exemple, disons qu'un Tp promène des chats. Vous pouvez créer un modèle Walk qui relie un Cat à un Tp.

class Walk < ActiveRecord::Base 
    belongs_to :cat 
    belongs_to :tp 
    attr_accessible :price, :duration, :interval # these attributes describe the Walk relationship 
end 

class Cat < ActiveRecord::Base 
    has_many :walks 
    has_many :tps, :through => :walks 
end 

class Tp < ActiveRecord::Base 
    has_many :walks 
    has_many :cats, :through => :walks 
end 

Maintenant, la relation est semblable à un has_and_belongs_to_many, mais vous pouvez inclure des métadonnées sur la relation de marche. De plus, disons qu'un Tp promène aussi des chiens. Vous pouvez convertir le belongs_to :cat en une relation polymorphe belongs_to :animal afin qu'un Tp puisse promener un chat, un chien, une souris, un lapin, un cheval, ... vous l'appelez.

class Walk < ActiveRecord::Base 
    belongs_to :animal, :polymorphic => true 
    belongs_to :tp 
    attr_accessible :price, :duration, :interval # these attributes describe the Walk relationship 
end 

class Cat < ActiveRecord::Base 
    has_many :walks, :as => :animal 
    has_many :tps, :through => :walks 
end 

class Dog < ActiveRecord::Base 
    has_many :walks, :as => :animal 
    has_many :tps, :through => :walks 
end 

class Tp < ActiveRecord::Base 
    has_many :walks 
    has_many :cats, :through => :walks, :source => :animal, :source_type => 'Cat' 
    has_many :dogs, :through => :walks, :source => :animal, :source_type => 'Dog' 
end 

Cette relation est créée avec une migration comme

class CreateWalks < ActiveRecord::Migration 
    def change 
    create_table :walks do |t| 
     t.belongs_to :animal, :polymorphic => true 
     t.belongs_to :tp 
    end 
    end 
end 
+0

donc si un Tp peut être associé à plusieurs entrées Cat et Dog, et un chat et un chien peuvent être associés à plusieurs entrées Tp, je devrais utiliser l'une des relations ActiveRecord plusieurs à plusieurs que vous avez décrites dans votre message? – jamesdlivesinatree

+0

Oui, c'est vrai. J'ai mis à jour la réponse avec des informations sur les relations plusieurs-à-plusieurs. –

+0

merci pour l'info, bonne réponse. – jamesdlivesinatree

0

Ce qui ne va pas

attr_accessible :dog_id1, :dog_id2, :dog_id3, :dog_id4, :cat_id1, :cat_id2, :cat_id3, :cat_id4, :star_id, :tp_id 

Votre modèle de chien a une tp_id et la has_many et belongs_to vous permettent de faire tp_instance.dogs pour obtenir un tableau de modèles pour chiens qui ont une correspondance tp_id

0

de supprimer le :dog_id(s) de le modèle TP et mettre :tp_id dans votre modèle de chien. Cela vous permettra d'avoir une relation un-à-plusieurs de TP à Dog

Questions connexes