6

Salut à tous, j'ai quelque chose d'une exigence intéressante pour mon projet. J'ai besoin d'une relation has_one où c'est soit une classe soit l'autre, mais sans héritage. Je pourrais m'en sortir avec l'héritage si c'est le seul moyen, mais les deux dossiers associés ont des données complètement différentes et ne sont pas liés du tout.RoR: has_one "ou l'autre"? (Ou, le polymorphisme sans l'héritage.)

Ce que je dois comprendre est quelque chose comme ce qui suit.

# 1. Foo never belongs to anything. 
# 2. Foo MUST have one assigned sub-record for validity. 
# 3. Foo can only have either Bar or Baz assigned. 
# 4. Bar and Baz have only ONE common property, and aren't 
# related in either data or implementation. 

class Foo < ActiveRecord::Base 
    # Attributes: id, name, value 
    has_one :assignment, :foreign_key => 'assigned_to', :readonly => true 
      # Could really use an :object_type for has_one here... 
end 

class Bar < ActiveRecord::Base 
    # Attributes: name,... 
end 

class Baz < ActiveRecord::Base 
    # Attributes: name,... 
end 

Foo a une affectation, de type soit Bar ou Baz; ils partagent seulement une colonne commune, alors peut-être que je peux en faire un objet parent. Cependant, si je les fais hériter d'un objet commun (quand les données qu'ils contiennent sont vraiment des oranges et des pommes) dois-je faire une table pour l'enregistrement? Puis-je m'en tirer si le disque est un disque abstrait, mais les enfants ne le sont pas? Je suppose que maintenant vous pouvez voir ma difficulté. Je suis plutôt nouveau à RoR mais l'aimer jusqu'à présent. Je suis sûr qu'il y a un moyen de contourner cela, mais je serai sidéré si je n'arrive pas à comprendre ce que c'est.

Répondre

8

Vous essayez de modéliser quelque chose qui ne correspond pas au paradigme de la base de données relationnelle. Toutes les références dans SQL ont une origine et une cible. Les associations polymorphes sont également un anti-pattern car il enfreint cette règle. Il devrait être un indice que c'est une conception brisée lorsque la documentation dit que vous devez renoncer à une contrainte d'intégrité référentielle pour le faire fonctionner!

Vous avez besoin de Foo pour avoir deux relations has_one: une pour Bar et une pour Baz. Ensuite, implémentez une logique de classe pour essayer de vous assurer qu'une seule référence est remplie dans une instance de Foo. Autrement dit, des références à Bar et Baz, il faut avoir une valeur et l'autre doit être nulle, mais c'est quelque chose que votre code doit vérifier et appliquer.

+0

Bon point, mais parfois, nous ne sommes pas entièrement libres de la conception des bases de données ou de leur relation. Surtout lorsque vous travaillez avec un produit ou une bibliothèque produite par quelqu'un d'autre. Les deux relations de has_one fonctionneront bien; merci pour votre perspicacité. –

0

Peut-être une façon de le faire, est de créer des associations has-one dans Foo, pour Bar et Baz. Ensuite, créez une méthode appelée affectation et affectation = qui peut être le seul moyen d'accéder à Bar et Baz. Vous pouvez vérifier lequel des deux has_ones n'est pas nul dans la méthode get et retourner celui-là. Dans la méthode d'affectation, vous pouvez vérifier quel est le type de la variable transmise et définir la relation has-one correcte avec cet objet et définir l'autre sur nil. Cela devrait couvrir toutes vos bases sans être trop compliqué.

Questions connexes